Analyse der Sentimente

Nachdem GerVADER2 die Sentimente aller Sätze im Korpus erkannt und wir im vorherigen Schritt alle objektiven Wörter auf Sentiment-Tendenzen untersucht haben, können die annotierten Sentiment-Werte nun auf höhere Ebenen (von Sätze zu Kommentaren, Blogs und Kampagnen) akkumuliert werden.

if (!require(readr)) {install.packages(readr)}; library(readr)
if (!require("tidytext")) {install.packages("tidytext")}; library("tidytext")
if (!require("textdata")) {install.packages("textdata")}; library("textdata")
if (!require("dplyr")) {install.packages("dplyr")}; library("dplyr")
if (!require("ggplot2")) {install.packages("ggplot2")}; library("ggplot2")
if (!require("tidyr")) {install.packages("tidyr")}; library("tidyr")
if (!require("stringr")) {install.packages("stringr")}; library("stringr")
if (!require("psych")) {install.packages("psych")}; library("psych")
if (!require("glue")) {install.packages("glue")}; library("glue")

Laden der Daten

filePath = "./data/GerVader2_adjusted_sentences.tsv"
GerVader2_sentences <-  read_tsv(file = filePath)
Rows: 1974909 Columns: 12
── Column specification ─────────────────────────────────────────────────────────────────────────────────────────────
Delimiter: "\t"
chr  (1): comment_text
dbl (10): project_id, blog_id, comment_id, sentence_id, compound, neg, neu, pos, wordCount, compound_alt
lgl  (1): is_moderator

ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
GerVader2_sentences

Normalisierung der Daten

Hier wird eine Funktion verwendet, die die Daten in Werte zwischen -1 und 1 skaliert. Zusätzlich wird ein Alpha-Wert verwendet, der die Verteilung der Werte optisch verständlicher macht. Je höher Alpha, desto stärker werden die Unterschiede zwischen den stärkeren Sentimenten erkennbar.

# das ist die von GerVADER verwendete Normalisiserungsfunktion
normalizeScore <- function(score, alpha=30){
  score_norm = score / sqrt(score ^ 2 + alpha)
  if (score_norm > 1){score_norm=1}
  if (score_norm <= -1){score_norm=-1}
  return (score_norm)
}

Sentimente pro Kommentar

Akkumulieren der Satz-Sentimente

alpha = 40

# starte mit Sentimente pro Satz
GerVader2_comments_nn <- GerVader2_sentences %>% 
  select(!c(neg, neu, pos)) %>% 
  group_by(project_id, blog_id, comment_id, is_moderator) %>% 
  # füge die Texte der Sätze zu Kommentaren zusammen
  mutate(
    comment_text = Reduce(f=paste, x=comment_text),
    ) %>% 
  group_by(project_id, blog_id, comment_id, is_moderator, comment_text) %>% 
  # errechne die Sentimentsummen der Kommentare und die Wortanzahl
  summarize(
    compound_alt = sum(compound_alt, na.rm=TRUE),
    compound = sum(compound, na.rm=TRUE),
    wordCount = sum(wordCount, na.rm=TRUE)
  )  
`summarise()` has grouped output by 'project_id', 'blog_id', 'comment_id', 'is_moderator'. You can override using the `.groups` argument.
GerVader2_comments <- GerVader2_comments_nn %>% 
  # normalisiere die Sentimentsummen mit einem gegebenen Alphawert
  mutate(
    compound_alt = normalizeScore(compound_alt, alpha),
    compound = normalizeScore(compound, alpha)
    ) %>% 
  # lade the Metadaten der Kommentare
inner_join(comments %>% select(project_id, blog_id, comment_id, comment_author))
Joining, by = c("project_id", "blog_id", "comment_id")
  
GerVader2_comments

Verteilung und Dichte der Kommentare

In den folgenden Plots werden die Verteilung und Dichte der Sentimente der Kommentare, jeweils vor und nach der Berücksichtigung der Sentiment-Tendenzen objektiver Worte, gezeigt.

# Verteilung der Sentiment-Kommentare vor Berücksichtigung der Tendenzen objektiver Worte
GerVader2_comments$compound_alt %>% hist(breaks=60, main="Verteilung Kommentare-Sentiment vor objektive Worten")

# Verteilung der Sentiment-Kommentare nach Berücksichtigung der Tend enzen objektiver Worte
GerVader2_comments$compound %>% hist(breaks=60, main="Verteilung Kommentare-Sentiment nach objektive Worten")


# Dichtefunktion der Sentiment-Kommentare
plot(density(GerVader2_comments$compound_alt), main="Dichtefunktion Kommentar-Sentimente")
lines(density(GerVader2_comments$compound), col=2, lty=2, lwd=3)

Hier wird erneut die Verteilung der Kommentar-Sentimente gezeigt. Die rote, strichlierte Linie markiert den Sentiment-Mittelwert. Dieser liegt bei 0,478.

Ebenso werden hier die Kommentardaten nach rein positiven, negativen und neutralen Kommentaren gefiltert. Somit zeigt sich, dass 750.230 positive, 18.426 negative und, danke Schritt 4, keine neutralen Kommentare erkannt wurden.

GerVader2_comments %>% 
  ggplot(aes(x=compound)) +
  geom_histogram(binwidth=0.05) +
  geom_vline(aes(xintercept=mean(compound)), linetype="dashed", color = "red") +
  ggtitle("Sentiment-Verteilung der Kommentare") +
  labs(x="Sentimentwert", "Menge")


mean(GerVader2_comments$compound)
[1] 0.4787203
GerVader2_comments %>% 
  filter(compound > 0)
GerVader2_comments %>% 
  filter(compound < 0)
GerVader2_comments %>% 
  filter(compound == 0)

Wortanzahl der Kommentare

Hier wird gezeigt, dass es eine signifikante, positive Korrelation zwischen der Länge eines Kommentars und dem Sentiment gibt.

# Korrelation zwischen Sentiment und Wortanzahl
cor.test(GerVader2_comments$wordCount, GerVader2_comments$compound)

    Pearson's product-moment correlation

data:  GerVader2_comments$wordCount and GerVader2_comments$compound
t = 347.04, df = 768654, p-value < 2.2e-16
alternative hypothesis: true correlation is not equal to 0
95 percent confidence interval:
 0.3661123 0.3699777
sample estimates:
      cor 
0.3680466 
"Statistiken der Wortanzahlen"
[1] "Statistiken der Wortanzahlen"
summary(GerVader2_comments$wordCount)
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
   0.00   40.00   66.00   79.71  103.00 2168.00 

Es gibt eine schwache, signifikante, positive Korrelation von 0,26 zwischen den erkannten Sentimenten von Kommentaren und ihrer Länge.

Visualisierung von Alpha

Der Effekt des Normalisierungsparameters Alpha wird im folgenden visualisiert. Bei kleinem Alpha ist die starke Tendenz zu sehr positiven Kommentaren sichtbar, Unterschiede zwischen den positiven Kommentaren sind schwerer erkennbar. Durch ein größeres Alpha werden die Abstände zwischen den sehr positiven Kommentaren scheinbar größer.

alpha_1 <- GerVader2_comments_nn$compound %>% 
  as.data.frame() %>% 
  mutate(compound = normalizeScore(., 1))%>% mutate(alpha = 1)
Bedingung hat Länge > 1 und nur das erste Element wird benutztBedingung hat Länge > 1 und nur das erste Element wird benutzt
alpha_15 <- GerVader2_comments_nn$compound %>% 
  as.data.frame() %>% 
  mutate(compound = normalizeScore(., 15))%>% mutate(alpha = 15)
Bedingung hat Länge > 1 und nur das erste Element wird benutztBedingung hat Länge > 1 und nur das erste Element wird benutzt
alpha_40 <- GerVader2_comments_nn$compound %>% 
  as.data.frame() %>% 
  mutate(compound = normalizeScore(., 40))%>% mutate(alpha = 40)
Bedingung hat Länge > 1 und nur das erste Element wird benutztBedingung hat Länge > 1 und nur das erste Element wird benutzt
alpha_90 <- GerVader2_comments_nn$compound %>% 
  as.data.frame() %>% 
  mutate(compound = normalizeScore(., 90))%>% mutate(alpha = 90)
Bedingung hat Länge > 1 und nur das erste Element wird benutztBedingung hat Länge > 1 und nur das erste Element wird benutzt
alpha_200 <- GerVader2_comments_nn$compound %>% 
  as.data.frame() %>% 
  mutate(compound = normalizeScore(., 200))%>% mutate(alpha = 200)
Bedingung hat Länge > 1 und nur das erste Element wird benutztBedingung hat Länge > 1 und nur das erste Element wird benutzt
alpha_30 <- GerVader2_comments_nn$compound %>% 
  as.data.frame() %>% 
  mutate(compound = normalizeScore(., 30))%>% mutate(alpha = 30)
Bedingung hat Länge > 1 und nur das erste Element wird benutztBedingung hat Länge > 1 und nur das erste Element wird benutzt
alpha_scores <- rbind(alpha_1, alpha_15, alpha_30, alpha_40, alpha_90, alpha_200 )

alpha_scores %>% 
  ggplot( aes(x=compound, color=alpha, fill=alpha)) +
    geom_histogram(alpha=.7, binwidth = 0.05) +
    facet_wrap(~alpha) +
    ggtitle("Sentimentverteilung der Kommentare für Alpha-Werte") +
    xlab("Sentiment") + ylab("")

Normalverteilung der Kommentar-Sentimente

Die folgenden Shapiro-Wilk-Tests ergeben, dass die Kommentar-Sentimente weder vor noch nach der Berücksichtigung der Sentiment-Tendenzen der objektiven Worte annähernd normalverteilt ist.

shapiro.test(GerVader2_comments$compound %>% sample(5000))

    Shapiro-Wilk normality test

data:  GerVader2_comments$compound %>% sample(5000)
W = 0.97549, p-value < 2.2e-16
shapiro.test(GerVader2_comments$compound_alt %>% sample(5000))

    Shapiro-Wilk normality test

data:  GerVader2_comments$compound_alt %>% sample(5000)
W = 0.95201, p-value < 2.2e-16

Sentimente pro Blogeintrag

Hier werden die durchschnittlichen Sentimente der Kommentare pro Blog errechnet.

GerVader_per_blog <- GerVader2_comments %>% 
  # lade die Metadaten der Blogeinträge
  inner_join(blogs, by=c("project_id", "blog_id")) %>% 
  group_by(project_id, blog_id, author, n_comments) %>% 
  # errechne die Sentiment-Mittelwerte pro blog_id
  summarize(
    SentimentMean = mean(compound, na.rm = TRUE),
    SentimentMean_alt = mean(compound_alt, na.rm = TRUE),
  ) %>% 
  # lade die Kampagnen-Metadaten (Teilnehmeranzahl)
  inner_join(projects %>% select(project_id, participants), by=c("project_id"))
`summarise()` has grouped output by 'project_id', 'blog_id', 'author'. You can override using the `.groups` argument.
GerVader_per_blog

Verteilung der Blogeintrag-Sentimente

Hier wird die Verteilung der der Blogeintrag-Sentimente visualisiert und auf Normalverteilung getestet. Das durchschnittlich Sentiment der Blogeintrag-Kommentare beträgt 0,493.

Der Shapiro-Wilk-Test weist nach, dass die Blogeintrag-Sentimente nicht annähernd normalverteilt sind.

# Verteilung der Blogeintrag-Sentimente
GerVader_per_blog %>% 
  ggplot(aes(x=SentimentMean)) +
  geom_histogram(binwidth=0.01) +
  geom_vline(aes(xintercept=mean(SentimentMean)), linetype="dashed", color = "red") +
  ggtitle("Sentiment-Verteilung der Blogeinträge") +
  labs(x="Sentimentwert", "Menge")


# Teste die Verteilung der Blogeintrag-Sentimente auf Normalverteilung
shapiro.test(GerVader_per_blog$SentimentMean)

    Shapiro-Wilk normality test

data:  GerVader_per_blog$SentimentMean
W = 0.99613, p-value = 4.302e-06
"Mittelwert der durhcschnittlichen Blogeintrag-Sentimente"
[1] "Mittelwert der durhcschnittlichen Blogeintrag-Sentimente"
mean(GerVader_per_blog$SentimentMean)
[1] 0.4932989

Sentimente pro Kampagne (Projekt)

Auch für die Analyse der Kampagnen werden die Sentimente der Kommentare nach Kampagnen gruppiert und ihr Mittelwert berechnet.

GerVader_per_project <- GerVader2_comments %>% 
  group_by(project_id) %>% 
  summarize(
    # errechne die Sentimentsumme und den Sentimentdurchschnitt
    SentimenSum = sum(compound),
    SentimentMean = mean(compound, na.rm = TRUE),
    SentimentMean_alt = mean(compound_alt, na.rm = TRUE),
    # errechne die Wortanzahl der Kommentare der Kampagne
    wordCount = sum(wordCount),
    # errechne die Anzahl an Kommentaren in einer Kampagne
    commentCount = n()
    ) %>% 
  # lade die Metadaten der Kampagnen, Kampagnenergebnisse und Blogeinträge
  inner_join(projects, by="project_id") %>% 
  inner_join(results, by="project_id") %>% 
  left_join(
    blogs %>% group_by(project_id, author) %>% summarize(n=n()) %>% select(project_id, author),
    by="project_id"
    ) %>% 
  left_join(
    blogs %>% group_by(project_id) %>% summarize(blogCount=n()) %>% select(project_id, blogCount), 
    by="project_id"
    ) %>% 
  # errechne die durchschnittliche Anzahl an Kommentaren pro Kampagnenteilnehmer
  # nenne das Ergebnis "engagement"
  mutate(engagement = commentCount / participants)
`summarise()` has grouped output by 'project_id'. You can override using the `.groups` argument.
# errechne die Laufzeit des Projekts
getRuntime <- function(start,end){
  start = strsplit(start, "[.]")
  start_day = (start[[1]][1]) %>% as.numeric() 
  start_month = (start[[1]][2]) %>% as.numeric() 
  start_year = (start[[1]][3]) %>% as.numeric() 
  end = strsplit(end, "[.]")
  end_day = (end[[1]][1]) %>% as.numeric() 
  end_month = (end[[1]][2]) %>% as.numeric() 
  end_year = (end[[1]][3]) %>% as.numeric() 
  return ((end_day+end_month*30+end_year*365)-(start_day+start_month*30+start_year*365))
}
GerVader_per_project$runtime = mapply(getRuntime, GerVader_per_project$start_date, GerVader_per_project$end_date)

GerVader_per_project
summary(GerVader_per_project)
   project_id     SentimenSum       SentimentMean    SentimentMean_alt   wordCount        commentCount  
 Min.   : 17.0   Min.   :   60.07   Min.   :0.3583   Min.   :0.1267    Min.   :   8661   Min.   :  120  
 1st Qu.:113.0   1st Qu.:  419.06   1st Qu.:0.4586   1st Qu.:0.2318    1st Qu.:  69991   1st Qu.:  890  
 Median :181.0   Median :  883.26   Median :0.4849   Median :0.2622    Median : 145794   Median : 1876  
 Mean   :176.4   Mean   : 1497.77   Mean   :0.4834   Mean   :0.2589    Mean   : 250554   Mean   : 3118  
 3rd Qu.:250.0   3rd Qu.: 2009.57   3rd Qu.:0.5108   3rd Qu.:0.2893    3rd Qu.: 335872   3rd Qu.: 4204  
 Max.   :304.0   Max.   :16501.41   Max.   :0.6131   Max.   :0.3791    Max.   :3198270   Max.   :34485  
                                                                                                        
      ...1         Unnamed: 0     Unnamed: 0.1   Unnamed: 0.1.1    href           category        
 Min.   : 16.0   Min.   : 16.0   Min.   : 16.0   Min.   : 16.0   Mode:logical   Length:221        
 1st Qu.:112.0   1st Qu.:112.0   1st Qu.:112.0   1st Qu.:112.0   NA's:221       Class :character  
 Median :180.0   Median :180.0   Median :180.0   Median :180.0                  Mode  :character  
 Mean   :175.4   Mean   :175.4   Mean   :175.4   Mean   :175.4                                    
 3rd Qu.:249.0   3rd Qu.:249.0   3rd Qu.:249.0   3rd Qu.:249.0                                    
 Max.   :303.0   Max.   :303.0   Max.   :303.0   Max.   :303.0                                    
                                                                                                  
    title           description     start_date          end_date          participants   weiterempfehlungsquote
 Length:221         Mode:logical   Length:221         Length:221         Min.   :   20   Min.   : 75.00        
 Class :character   NA's:221       Class :character   Class :character   1st Qu.:  550   1st Qu.: 91.00        
 Mode  :character                  Mode  :character   Mode  :character   Median : 1500   Median : 93.00        
                                                                         Mean   : 2177   Mean   : 92.51        
                                                                         3rd Qu.: 3000   3rd Qu.: 96.00        
                                                                         Max.   :11000   Max.   :100.00        
                                                                         NA's   :114     NA's   :16            
  rating_value    review_count    content             author            blogCount       engagement      
 Min.   :3.500   Min.   :  20   Length:221         Length:221         Min.   : 3.00   Min.   :  0.3009  
 1st Qu.:4.400   1st Qu.: 409   Class :character   Class :character   1st Qu.: 8.00   1st Qu.:  0.6957  
 Median :4.500   Median : 895   Mode  :character   Mode  :character   Median :10.00   Median :  0.9231  
 Mean   :4.451   Mean   :1630                                         Mean   :11.72   Mean   :  5.5875  
 3rd Qu.:4.600   3rd Qu.:2335                                         3rd Qu.:15.00   3rd Qu.:  2.3508  
 Max.   :4.800   Max.   :8357                                         Max.   :32.00   Max.   :252.7500  
 NA's   :160     NA's   :160                                                          NA's   :114       
    runtime      
 Min.   : 27.00  
 1st Qu.: 43.00  
 Median : 48.00  
 Mean   : 54.05  
 3rd Qu.: 57.00  
 Max.   :359.00  
                 

Verteilung der Kampagnen-Sentimente

Hier werden die Verteilung der Kampagnen-Sentimente visualisiert und auf Normalverteilung getestet. Die Kampagnen haben im Schnitt durchschnittliche Kommentar-Sentimente von 0,483.

Der Shapiro-Wilk-Test ergibt, dass die durchschnittlichen Kommentar-Sentimente pro Kampagne annähernd normalverteilt sind.

GerVader_per_project %>% 
  ggplot(aes(x=SentimentMean)) +
  geom_histogram(binwidth=0.005) +
  geom_vline(aes(xintercept=mean(SentimentMean)), linetype="dashed", color = "red") +
  ggtitle("Sentiment-Verteilung der Projekte") +
  labs(x="Sentimentwert", "Menge")


"Durchschnittliche Kampagnen-Sentimente"
[1] "Durchschnittliche Kampagnen-Sentimente"
mean(GerVader_per_project$SentimentMean)
[1] 0.4833905
"Negativster Kampagnen-Sentiment-Mittelwert"
[1] "Negativster Kampagnen-Sentiment-Mittelwert"
min(GerVader_per_project$SentimentMean)
[1] 0.3582805
# Teste die Kampagnen-Sentimente auf Normalverteilung
shapiro.test(GerVader_per_project$SentimentMean)

    Shapiro-Wilk normality test

data:  GerVader_per_project$SentimentMean
W = 0.99447, p-value = 0.5955

Korrelationen zwischen Kampagneneigenschaften und ihren Ergebnissen

Im folgenden werden die Ergebnisse der Kampagnen, also der erkannten Sentiment, den durchschnittlichen Kundenbewertungen und den durchschnittlichen Weiterempfehlungsquoten, auf Korrelation miteinander und mit anderen Variablen, nämlich der Anzahl an Blgoeinträgen und Teilnehmern pro Kampagne, der Laufzeit jeder Kampagne und dem Engagement, dass die Teilnehmer im Schnitt zeigten.

GerVader_per_project %>% 
  select(
    SentimentMean, 
    weiterempfehlungsquote, 
    rating_value, 
    blogCount,
    participants,
    runtime,
    engagement
    ) %>% 
  pairs.panels()

Im folgenden werden die entdeckten Korrelationen auf Signifikanz getestet.

Es gibt ein signifikante, wenn auch nicht starke, Korrelation zwischen den durch GerVader2 erkannten, durchschnittlichen Sentimenten der Projekte und ihren Weiterempfehlungsraten (0,20) und Bewertungen (0,33).

Ebenso gibt es eine signifikante, schwach negative Korrelation (-0,24) zwischen dem Sentiment der Kommentare pro Kampagne und der Anzahl an Blogeinträgen über die Kampagnenlaufzeit.

cor.test(GerVader_per_project$SentimentMean, GerVader_per_project$weiterempfehlungsquote)

    Pearson's product-moment correlation

data:  GerVader_per_project$SentimentMean and GerVader_per_project$weiterempfehlungsquote
t = 2.8702, df = 203, p-value = 0.004536
alternative hypothesis: true correlation is not equal to 0
95 percent confidence interval:
 0.06212901 0.32570350
sample estimates:
      cor 
0.1974827 
cor.test(GerVader_per_project$SentimentMean, GerVader_per_project$rating_value)

    Pearson's product-moment correlation

data:  GerVader_per_project$SentimentMean and GerVader_per_project$rating_value
t = 2.6854, df = 59, p-value = 0.009393
alternative hypothesis: true correlation is not equal to 0
95 percent confidence interval:
 0.08528372 0.53719411
sample estimates:
      cor 
0.3300169 
cor.test(GerVader_per_project$SentimentMean, GerVader_per_project$blogCount)

    Pearson's product-moment correlation

data:  GerVader_per_project$SentimentMean and GerVader_per_project$blogCount
t = -3.5894, df = 219, p-value = 0.000409
alternative hypothesis: true correlation is not equal to 0
95 percent confidence interval:
 -0.3565949 -0.1070762
sample estimates:
       cor 
-0.2357165 
cor.test(GerVader_per_project$SentimentMean, GerVader_per_project$participants)

    Pearson's product-moment correlation

data:  GerVader_per_project$SentimentMean and GerVader_per_project$participants
t = -1.8717, df = 105, p-value = 0.06404
alternative hypothesis: true correlation is not equal to 0
95 percent confidence interval:
 -0.35735059  0.01053485
sample estimates:
      cor 
-0.179683 
cor.test(GerVader_per_project$SentimentMean, GerVader_per_project$runtime)

    Pearson's product-moment correlation

data:  GerVader_per_project$SentimentMean and GerVader_per_project$runtime
t = 1.2796, df = 219, p-value = 0.202
alternative hypothesis: true correlation is not equal to 0
95 percent confidence interval:
 -0.04635365  0.21566402
sample estimates:
       cor 
0.08614457 
cor.test(GerVader_per_project$SentimentMean, GerVader_per_project$engagement)

    Pearson's product-moment correlation

data:  GerVader_per_project$SentimentMean and GerVader_per_project$engagement
t = 1.3629, df = 105, p-value = 0.1758
alternative hypothesis: true correlation is not equal to 0
95 percent confidence interval:
 -0.05950816  0.31384245
sample estimates:
      cor 
0.1318398 

Nun werden die angeblich signifikanten Korrelationen genauer visualisiert.

GerVader_per_project %>% 
  ggplot(aes(weiterempfehlungsquote, SentimentMean)) +
  geom_jitter() +
  ggtitle("Korrelation zwischen Sentiment pro Projekt und Weiterempfehlungsrate")+
  ylab("durchschn. Sentiment pro Projekt") + xlab("durchschn. Weiterempfehlungsrate")

  
GerVader_per_project %>% 
  ggplot(aes(rating_value, SentimentMean)) +
  geom_jitter() +
  ggtitle("Korrelation zwischen Sentiment pro Projekt und  Kundenbewertung")+
  ylab("durchschn. Sentiment pro Projekt") + xlab("durchschn. Kundenbewertung")

  
GerVader_per_project %>% 
  ggplot(aes(blogCount, SentimentMean)) +
  geom_jitter() +
  ggtitle("Korrelation zwischen Sentiment pro Projekt und Anzahl an Blogeinträgen")+
  ylab("durchschn. Sentiment pro Projekt") + xlab("Blogeinträge")

Kampagnenresultate pro Domäne (category)

Im folgenden werden pro Domäne die durchschnittlichen Sentimente, Teilnehmerbewertungen, Weiterempfehlungsquoten und die Varianz der Sentimente berechnet.

"Domänen der Kampagnen"
[1] "Domänen der Kampagnen"
projects$category %>% unique()
 [1] "Haushalt & Reinigung" "Tiere"                "Freizeit & Reisen"    "Beauty & Pflege"     
 [5] "Technik & Online"     "Food & Snacks"        "Getränke"             "Sonstiges"           
 [9] "Gesundheit"           "Shops"               
GerVader2_per_category <- GerVader2_comments %>% 
  # lade Metadaten der Kampagnen und ihrer Ergebnisse
  inner_join(projects, by="project_id") %>% 
  inner_join(results, by="project_id") %>% 
  group_by(category) %>% 
  # Statistikenpro Domäne
   summarize(
     # Sentiment-Mittelwert
    SentimentMean = mean(compound, na.rm = TRUE),
    # Kommentaranzahl
    comment_count = n(),
    # durchschnittliche Teilnehmerbewertung
    RatingMean = mean(rating_value, na.rm=TRUE),
    # durchschnittliche Weiterempfehlungsrate
    WeiterempfehlungsquoteMean = mean(weiterempfehlungsquote, na.rm=TRUE),
    # Varianz der Sentimente
    variance = var(compound, na.rm=TRUE)
    ) %>% 
  arrange(desc(SentimentMean))

GerVader2_per_category
GerVader2_per_category$SentimentMean %>% barplot(legend=GerVader2_per_category$category)

Analyse der Kampagnenmanager

Hier wird das jeweilige Engagement der Teilnehmer pro Kampagnenmanager gezeigt.

GerVader_per_project %>% 
  select(project_id, author, engagement) %>% 
  arrange(desc(engagement))

Hier wird ein Datensatz mit den durchschnittlichen Kommentar-Sentimenten, Teilnehmerbewertungen und Weiterempfehlungsquoten pro Kampagnenmanager, sowie der Anzahl verwalteter Kampagnen und dem angeregten Engagement, also der durchschnittlichen Anzahl an Kommentaren, errechnet.

GerVader_projects_per_author <- GerVader_per_project %>% 
  group_by(author) %>% 
  summarise(
    SentimentMean = mean(SentimentMean, na.rm = TRUE),
    weiterempfehlungsquote = mean(weiterempfehlungsquote, na.rm = TRUE),
    rating_value = mean(rating_value, na.rm = TRUE),
    n_projects = n(),
    engagement = mean(commentCount / participants, na.rm = TRUE)
  ) %>% 
  arrange(desc(SentimentMean))
GerVader_projects_per_author

Korrelationen der Ergebnisse pro Kampagnenmanager

Hier werden die Erfolgsmetriken pro Kampagnenmanager auf Korrelationen untersucht.

GerVader_projects_per_author %>% 
  select(
    SentimentMean, 
    weiterempfehlungsquote, 
    rating_value, 
    n_projects,
    engagement
    ) %>% 
  pairs.panels()

Die Korrelationen sind allesamt nicht signifikant. Das könnte auch daran liegen, dass nur sehr wenige verschiedene Kampagnenmanager in den Daten vorliegen, vielleicht ergeben sich im großen Ganzen signifikantere Trends.

cor.test(GerVader_projects_per_author$SentimentMean, GerVader_projects_per_author$weiterempfehlungsquote)

    Pearson's product-moment correlation

data:  GerVader_projects_per_author$SentimentMean and GerVader_projects_per_author$weiterempfehlungsquote
t = 0.23743, df = 35, p-value = 0.8137
alternative hypothesis: true correlation is not equal to 0
95 percent confidence interval:
 -0.2876554  0.3594497
sample estimates:
       cor 
0.04010124 
cor.test(GerVader_projects_per_author$SentimentMean, GerVader_projects_per_author$rating_value)

    Pearson's product-moment correlation

data:  GerVader_projects_per_author$SentimentMean and GerVader_projects_per_author$rating_value
t = 0.93286, df = 13, p-value = 0.3679
alternative hypothesis: true correlation is not equal to 0
95 percent confidence interval:
 -0.3003172  0.6760036
sample estimates:
      cor 
0.2504798 
cor.test(GerVader_projects_per_author$SentimentMean, GerVader_projects_per_author$n_projects)

    Pearson's product-moment correlation

data:  GerVader_projects_per_author$SentimentMean and GerVader_projects_per_author$n_projects
t = 1.5713, df = 35, p-value = 0.1251
alternative hypothesis: true correlation is not equal to 0
95 percent confidence interval:
 -0.07343163  0.53612248
sample estimates:
     cor 
0.256695 
cor.test(GerVader_projects_per_author$rating_value, GerVader_projects_per_author$n_projects)

    Pearson's product-moment correlation

data:  GerVader_projects_per_author$rating_value and GerVader_projects_per_author$n_projects
t = -0.76534, df = 13, p-value = 0.4577
alternative hypothesis: true correlation is not equal to 0
95 percent confidence interval:
 -0.6506912  0.3408811
sample estimates:
     cor 
-0.20764 
cor.test(GerVader_projects_per_author$weiterempfehlungsquote, GerVader_projects_per_author$engagement)

    Pearson's product-moment correlation

data:  GerVader_projects_per_author$weiterempfehlungsquote and GerVader_projects_per_author$engagement
t = 1.4362, df = 18, p-value = 0.1681
alternative hypothesis: true correlation is not equal to 0
95 percent confidence interval:
 -0.1420323  0.6683323
sample estimates:
      cor 
0.3206415 

Kampagnen-Sentimente über ihre Laufzeit

Als nächstes werden die Kommentar-Sentimente der Blogeinträge jeder Kampagne visualisiert, um Sentiment-Trends über die Kampagnenentwicklung erkennbar zu machen.

# Funktion zur Visualisierung von Sentiment-Entwicklungen einer Kampagne

SentimentEntwicklung <- function(GerVader_per_blog, project_ids=c(1:100000000), showLegend=TRUE, opacity=1, points=TRUE, title="") {
  GerVader_per_blog %>% 
    mutate(
      project_id = factor(project_id),
    ) %>% 
    filter(project_id %in% project_ids) %>% 
    ggplot(aes(blog_id_alt, SentimentMean, color=project_id)) +
      geom_line(alpha=opacity, show.legend = showLegend) +
      geom_point(show.legend = showLegend, alpha=points) +
      ggtitle(glue("Sentiment-Entwicklung für Kampagne(n) {title}")) +
      xlab("Blog ID") +
      geom_point() %>% 
    print()
}
# Kampagne 17
SentimentEntwicklung(GerVader_per_blog, project_ids=17, title="#17")
geom_point: na.rm = FALSE
stat_identity: na.rm = FALSE
position_identity 
Fehler in FUN(X[[i]], ...) : Objekt 'blog_id_alt' nicht gefunden

Analyse von bestimmten Kampagnenmanagern und ihren Kampagnen

Hier werden die Kampagnenmanager “lesofy” und insbesondere “nellisa” genauer unter die Lupe genommen.

Detailanalyse: Kampagnenmanager “Nellisa” und ihre Kampagne #198

Die Kampagne 198 hat, wie oben ersichtlich, ein Sentimenttief bei den ersten Blogeinträgen. Das wird hier genauer untersucht.

Vergleiche die Anzahl negativer Kommentare mit dem durchschnittlichen Kommentarsentiment pro Blogeintrag über die Kampagnenentwicklung

Die folgende Grafik zeigt, dass es während dem Tief der durchschnittlichen Sentimente (türkis) der ersten Blogeinträge auch relativ viele negative Kommentare (orange, strichliert) gab.

Vergleiche die Anzahl sehr positiver Kommentare mit dem durchschnittlichen Kommentarsentiment pro Blogeintrag über die Kampagnenentwicklung

Die folgende Grafik zeigt, dass es während dem Tief der durchschnittlichen Sentimente (türkis) auch relativ weniger sehr positive Kommentare (pink, strichliert) gab.

Hier werden nun die Anzahl der Kommentare pro Blogeintrag der Kampagne 198 visualisiert. Bei Blogeintrag 7 gibt es besonders viele Kommentare, darum wird mittels Histogramm die Verteilung der Kommentar-Sentimente in Blogeintrag 7 der Kampagne 198 abgebildet.

Negative Kommentare in Kampagne 189

Super-negative Kommentare

Hier werden ein paar Blogs auf ihre negativsten Kommentare Stichprobenartig untersucht.

Kommentar-Sentimente pro Teilnehmer

Die Teilnehmer nehmen veschieden oft an Kampagnen teil, schreiben verschieden lange und emotion unterschiedlich geladene Texte. Das wird hier untersucht.

Hier sind ein paar informative Plots zu den Verteilungen der Userkommentare.

Genauere Untersuchtung des Users “blackstar”

Die Kommentare des Users “blackstar”, dessen Kommentare tendenziell negativ sind, werden hier herausgefiltert, damit sie inhaltlich analysiert werden können. Sie scheinen Beschwerden über Lieferprobleme zu enthalten.

LS0tCnRpdGxlOiAiMDZfR2VyVkFERVIyX0FuYWx5c2UiCm91dHB1dDogaHRtbF9ub3RlYm9vawotLS0KCiMgQW5hbHlzZSBkZXIgU2VudGltZW50ZQpOYWNoZGVtICpHZXJWQURFUjIqIGRpZSBTZW50aW1lbnRlIGFsbGVyIFPDpHR6ZSBpbSBLb3JwdXMgZXJrYW5udCB1bmQgd2lyIGltIHZvcmhlcmlnZW4gU2Nocml0dCBhbGxlIG9iamVrdGl2ZW4gV8O2cnRlciBhdWYgU2VudGltZW50LVRlbmRlbnplbiB1bnRlcnN1Y2h0IGhhYmVuLCBrw7ZubmVuIGRpZSBhbm5vdGllcnRlbiBTZW50aW1lbnQtV2VydGUgbnVuIGF1ZiBow7ZoZXJlIEViZW5lbiAodm9uIFPDpHR6ZSB6dSBLb21tZW50YXJlbiwgQmxvZ3MgdW5kIEthbXBhZ25lbikgYWtrdW11bGllcnQgd2VyZGVuLgoKYGBge3J9CmlmICghcmVxdWlyZShyZWFkcikpIHtpbnN0YWxsLnBhY2thZ2VzKHJlYWRyKX07IGxpYnJhcnkocmVhZHIpCmlmICghcmVxdWlyZSgidGlkeXRleHQiKSkge2luc3RhbGwucGFja2FnZXMoInRpZHl0ZXh0Iil9OyBsaWJyYXJ5KCJ0aWR5dGV4dCIpCmlmICghcmVxdWlyZSgidGV4dGRhdGEiKSkge2luc3RhbGwucGFja2FnZXMoInRleHRkYXRhIil9OyBsaWJyYXJ5KCJ0ZXh0ZGF0YSIpCmlmICghcmVxdWlyZSgiZHBseXIiKSkge2luc3RhbGwucGFja2FnZXMoImRwbHlyIil9OyBsaWJyYXJ5KCJkcGx5ciIpCmlmICghcmVxdWlyZSgiZ2dwbG90MiIpKSB7aW5zdGFsbC5wYWNrYWdlcygiZ2dwbG90MiIpfTsgbGlicmFyeSgiZ2dwbG90MiIpCmlmICghcmVxdWlyZSgidGlkeXIiKSkge2luc3RhbGwucGFja2FnZXMoInRpZHlyIil9OyBsaWJyYXJ5KCJ0aWR5ciIpCmlmICghcmVxdWlyZSgic3RyaW5nciIpKSB7aW5zdGFsbC5wYWNrYWdlcygic3RyaW5nciIpfTsgbGlicmFyeSgic3RyaW5nciIpCmlmICghcmVxdWlyZSgicHN5Y2giKSkge2luc3RhbGwucGFja2FnZXMoInBzeWNoIil9OyBsaWJyYXJ5KCJwc3ljaCIpCmlmICghcmVxdWlyZSgiZ2x1ZSIpKSB7aW5zdGFsbC5wYWNrYWdlcygiZ2x1ZSIpfTsgbGlicmFyeSgiZ2x1ZSIpCmBgYAoKCgoKCgoKIyMgTGFkZW4gZGVyIERhdGVuCmBgYHtyfQpmaWxlUGF0aCA9ICIuL2RhdGEvR2VyVmFkZXIyX2FkanVzdGVkX3NlbnRlbmNlcy50c3YiCkdlclZhZGVyMl9zZW50ZW5jZXMgPC0gIHJlYWRfdHN2KGZpbGUgPSBmaWxlUGF0aCkKR2VyVmFkZXIyX3NlbnRlbmNlcwpgYGAKCgoKIyMgTm9ybWFsaXNpZXJ1bmcgZGVyIERhdGVuCkhpZXIgd2lyZCBlaW5lIEZ1bmt0aW9uIHZlcndlbmRldCwgZGllIGRpZSBEYXRlbiBpbiBXZXJ0ZSB6d2lzY2hlbiAtMSB1bmQgMSBza2FsaWVydC4gWnVzw6R0emxpY2ggd2lyZCBlaW4gQWxwaGEtV2VydCB2ZXJ3ZW5kZXQsIGRlciBkaWUgVmVydGVpbHVuZyBkZXIgV2VydGUgb3B0aXNjaCB2ZXJzdMOkbmRsaWNoZXIgbWFjaHQuIEplIGjDtmhlciBBbHBoYSwgZGVzdG8gc3TDpHJrZXIgd2VyZGVuIGRpZSBVbnRlcnNjaGllZGUgendpc2NoZW4gZGVuIHN0w6Rya2VyZW4gU2VudGltZW50ZW4gZXJrZW5uYmFyLgoKYGBge3J9CiMgZGFzIGlzdCBkaWUgdm9uIEdlclZBREVSIHZlcndlbmRldGUgTm9ybWFsaXNpc2VydW5nc2Z1bmt0aW9uCm5vcm1hbGl6ZVNjb3JlIDwtIGZ1bmN0aW9uKHNjb3JlLCBhbHBoYT0zMCl7CiAgc2NvcmVfbm9ybSA9IHNjb3JlIC8gc3FydChzY29yZSBeIDIgKyBhbHBoYSkKICBpZiAoc2NvcmVfbm9ybSA+IDEpe3Njb3JlX25vcm09MX0KICBpZiAoc2NvcmVfbm9ybSA8PSAtMSl7c2NvcmVfbm9ybT0tMX0KICByZXR1cm4gKHNjb3JlX25vcm0pCn0KYGBgCgoKIyMgU2VudGltZW50ZSBwcm8gS29tbWVudGFyCiMjIyBBa2t1bXVsaWVyZW4gZGVyIFNhdHotU2VudGltZW50ZQpgYGB7cn0KYWxwaGEgPSA0MAoKIyBzdGFydGUgbWl0IFNlbnRpbWVudGUgcHJvIFNhdHoKR2VyVmFkZXIyX2NvbW1lbnRzX25uIDwtIEdlclZhZGVyMl9zZW50ZW5jZXMgJT4lIAogIHNlbGVjdCghYyhuZWcsIG5ldSwgcG9zKSkgJT4lIAogIGdyb3VwX2J5KHByb2plY3RfaWQsIGJsb2dfaWQsIGNvbW1lbnRfaWQsIGlzX21vZGVyYXRvcikgJT4lIAogICMgZsO8Z2UgZGllIFRleHRlIGRlciBTw6R0emUgenUgS29tbWVudGFyZW4genVzYW1tZW4KICBtdXRhdGUoCiAgICBjb21tZW50X3RleHQgPSBSZWR1Y2UoZj1wYXN0ZSwgeD1jb21tZW50X3RleHQpLAogICAgKSAlPiUgCiAgZ3JvdXBfYnkocHJvamVjdF9pZCwgYmxvZ19pZCwgY29tbWVudF9pZCwgaXNfbW9kZXJhdG9yLCBjb21tZW50X3RleHQpICU+JSAKICAjIGVycmVjaG5lIGRpZSBTZW50aW1lbnRzdW1tZW4gZGVyIEtvbW1lbnRhcmUgdW5kIGRpZSBXb3J0YW56YWhsCiAgc3VtbWFyaXplKAogICAgY29tcG91bmRfYWx0ID0gc3VtKGNvbXBvdW5kX2FsdCwgbmEucm09VFJVRSksCiAgICBjb21wb3VuZCA9IHN1bShjb21wb3VuZCwgbmEucm09VFJVRSksCiAgICB3b3JkQ291bnQgPSBzdW0od29yZENvdW50LCBuYS5ybT1UUlVFKQogICkgIAoKR2VyVmFkZXIyX2NvbW1lbnRzIDwtIEdlclZhZGVyMl9jb21tZW50c19ubiAlPiUgCiAgIyBub3JtYWxpc2llcmUgZGllIFNlbnRpbWVudHN1bW1lbiBtaXQgZWluZW0gZ2VnZWJlbmVuIEFscGhhd2VydAogIG11dGF0ZSgKICAgIGNvbXBvdW5kX2FsdCA9IG5vcm1hbGl6ZVNjb3JlKGNvbXBvdW5kX2FsdCwgYWxwaGEpLAogICAgY29tcG91bmQgPSBub3JtYWxpemVTY29yZShjb21wb3VuZCwgYWxwaGEpCiAgICApICU+JSAKICAjIGxhZGUgdGhlIE1ldGFkYXRlbiBkZXIgS29tbWVudGFyZQppbm5lcl9qb2luKGNvbW1lbnRzICU+JSBzZWxlY3QocHJvamVjdF9pZCwgYmxvZ19pZCwgY29tbWVudF9pZCwgY29tbWVudF9hdXRob3IpKQogIApHZXJWYWRlcjJfY29tbWVudHMKYGBgCgoKIyMjIFZlcnRlaWx1bmcgdW5kIERpY2h0ZSBkZXIgS29tbWVudGFyZSAKSW4gZGVuIGZvbGdlbmRlbiBQbG90cyB3ZXJkZW4gZGllIFZlcnRlaWx1bmcgdW5kIERpY2h0ZSBkZXIgU2VudGltZW50ZSBkZXIgS29tbWVudGFyZSwgamV3ZWlscyB2b3IgdW5kIG5hY2ggZGVyIEJlcsO8Y2tzaWNodGlndW5nIGRlciBTZW50aW1lbnQtVGVuZGVuemVuIG9iamVrdGl2ZXIgV29ydGUsIGdlemVpZ3QuCgpgYGB7cn0KIyBWZXJ0ZWlsdW5nIGRlciBTZW50aW1lbnQtS29tbWVudGFyZSB2b3IgQmVyw7xja3NpY2h0aWd1bmcgZGVyIFRlbmRlbnplbiBvYmpla3RpdmVyIFdvcnRlCkdlclZhZGVyMl9jb21tZW50cyRjb21wb3VuZF9hbHQgJT4lIGhpc3QoYnJlYWtzPTYwLCBtYWluPSJWZXJ0ZWlsdW5nIEtvbW1lbnRhcmUtU2VudGltZW50IHZvciBvYmpla3RpdmUgV29ydGVuIikKIyBWZXJ0ZWlsdW5nIGRlciBTZW50aW1lbnQtS29tbWVudGFyZSBuYWNoIEJlcsO8Y2tzaWNodGlndW5nIGRlciBUZW5kIGVuemVuIG9iamVrdGl2ZXIgV29ydGUKR2VyVmFkZXIyX2NvbW1lbnRzJGNvbXBvdW5kICU+JSBoaXN0KGJyZWFrcz02MCwgbWFpbj0iVmVydGVpbHVuZyBLb21tZW50YXJlLVNlbnRpbWVudCBuYWNoIG9iamVrdGl2ZSBXb3J0ZW4iKQoKIyBEaWNodGVmdW5rdGlvbiBkZXIgU2VudGltZW50LUtvbW1lbnRhcmUKcGxvdChkZW5zaXR5KEdlclZhZGVyMl9jb21tZW50cyRjb21wb3VuZF9hbHQpLCBtYWluPSJEaWNodGVmdW5rdGlvbiBLb21tZW50YXItU2VudGltZW50ZSIpCmxpbmVzKGRlbnNpdHkoR2VyVmFkZXIyX2NvbW1lbnRzJGNvbXBvdW5kKSwgY29sPTIsIGx0eT0yLCBsd2Q9MykKCmBgYApIaWVyIHdpcmQgZXJuZXV0IGRpZSBWZXJ0ZWlsdW5nIGRlciBLb21tZW50YXItU2VudGltZW50ZSBnZXplaWd0LiBEaWUgcm90ZSwgc3RyaWNobGllcnRlIExpbmllIG1hcmtpZXJ0IGRlbiBTZW50aW1lbnQtTWl0dGVsd2VydC4gRGllc2VyIGxpZWd0IGJlaSAwLDQ3OC4KCkViZW5zbyB3ZXJkZW4gaGllciBkaWUgS29tbWVudGFyZGF0ZW4gbmFjaCByZWluIHBvc2l0aXZlbiwgbmVnYXRpdmVuIHVuZCBuZXV0cmFsZW4gS29tbWVudGFyZW4gZ2VmaWx0ZXJ0LiBTb21pdCB6ZWlndCBzaWNoLCBkYXNzIDc1MC4yMzAgcG9zaXRpdmUsIDE4LjQyNiBuZWdhdGl2ZSB1bmQsIGRhbmtlIFNjaHJpdHQgNCwga2VpbmUgbmV1dHJhbGVuIEtvbW1lbnRhcmUgZXJrYW5udCB3dXJkZW4uIAoKYGBge3J9CkdlclZhZGVyMl9jb21tZW50cyAlPiUgCiAgZ2dwbG90KGFlcyh4PWNvbXBvdW5kKSkgKwogIGdlb21faGlzdG9ncmFtKGJpbndpZHRoPTAuMDUpICsKICBnZW9tX3ZsaW5lKGFlcyh4aW50ZXJjZXB0PW1lYW4oY29tcG91bmQpKSwgbGluZXR5cGU9ImRhc2hlZCIsIGNvbG9yID0gInJlZCIpICsKICBnZ3RpdGxlKCJTZW50aW1lbnQtVmVydGVpbHVuZyBkZXIgS29tbWVudGFyZSIpICsKICBsYWJzKHg9IlNlbnRpbWVudHdlcnQiLCAiTWVuZ2UiKQoKbWVhbihHZXJWYWRlcjJfY29tbWVudHMkY29tcG91bmQpCgpHZXJWYWRlcjJfY29tbWVudHMgJT4lIAogIGZpbHRlcihjb21wb3VuZCA+IDApCkdlclZhZGVyMl9jb21tZW50cyAlPiUgCiAgZmlsdGVyKGNvbXBvdW5kIDwgMCkKR2VyVmFkZXIyX2NvbW1lbnRzICU+JSAKICBmaWx0ZXIoY29tcG91bmQgPT0gMCkKYGBgCgoKIyMjIFdvcnRhbnphaGwgZGVyIEtvbW1lbnRhcmUKSGllciB3aXJkIGdlemVpZ3QsIGRhc3MgZXMgZWluZSBzaWduaWZpa2FudGUsIHBvc2l0aXZlIEtvcnJlbGF0aW9uIHp3aXNjaGVuIGRlciBMw6RuZ2UgZWluZXMgS29tbWVudGFycyB1bmQgZGVtIFNlbnRpbWVudCBnaWJ0LgoKYGBge3J9CiMgS29ycmVsYXRpb24gendpc2NoZW4gU2VudGltZW50IHVuZCBXb3J0YW56YWhsCmNvci50ZXN0KEdlclZhZGVyMl9jb21tZW50cyR3b3JkQ291bnQsIEdlclZhZGVyMl9jb21tZW50cyRjb21wb3VuZCkKIlN0YXRpc3Rpa2VuIGRlciBXb3J0YW56YWhsZW4iCnN1bW1hcnkoR2VyVmFkZXIyX2NvbW1lbnRzJHdvcmRDb3VudCkKYGBgCgpFcyBnaWJ0IGVpbmUgc2Nod2FjaGUsIHNpZ25pZmlrYW50ZSwgcG9zaXRpdmUgS29ycmVsYXRpb24gdm9uIDAsMjYgendpc2NoZW4gZGVuIGVya2FubnRlbiBTZW50aW1lbnRlbiB2b24gS29tbWVudGFyZW4gdW5kIGlocmVyIEzDpG5nZS4KCgojIyMgVmlzdWFsaXNpZXJ1bmcgdm9uIEFscGhhCkRlciBFZmZla3QgZGVzIE5vcm1hbGlzaWVydW5nc3BhcmFtZXRlcnMgQWxwaGEgd2lyZCBpbSBmb2xnZW5kZW4gdmlzdWFsaXNpZXJ0LiAKQmVpIGtsZWluZW0gQWxwaGEgaXN0IGRpZSBzdGFya2UgVGVuZGVueiB6dSBzZWhyIHBvc2l0aXZlbiBLb21tZW50YXJlbiBzaWNodGJhciwgVW50ZXJzY2hpZWRlIHp3aXNjaGVuIGRlbiBwb3NpdGl2ZW4gS29tbWVudGFyZW4gc2luZCBzY2h3ZXJlciBlcmtlbm5iYXIuIER1cmNoIGVpbiBncsO2w59lcmVzIEFscGhhIHdlcmRlbiBkaWUgQWJzdMOkbmRlIHp3aXNjaGVuIGRlbiBzZWhyIHBvc2l0aXZlbiBLb21tZW50YXJlbiBzY2hlaW5iYXIgZ3LDtsOfZXIuCgpgYGB7cn0KYWxwaGFfMSA8LSBHZXJWYWRlcjJfY29tbWVudHNfbm4kY29tcG91bmQgJT4lIAogIGFzLmRhdGEuZnJhbWUoKSAlPiUgCiAgbXV0YXRlKGNvbXBvdW5kID0gbm9ybWFsaXplU2NvcmUoLiwgMSkpJT4lIG11dGF0ZShhbHBoYSA9IDEpCmFscGhhXzE1IDwtIEdlclZhZGVyMl9jb21tZW50c19ubiRjb21wb3VuZCAlPiUgCiAgYXMuZGF0YS5mcmFtZSgpICU+JSAKICBtdXRhdGUoY29tcG91bmQgPSBub3JtYWxpemVTY29yZSguLCAxNSkpJT4lIG11dGF0ZShhbHBoYSA9IDE1KQphbHBoYV80MCA8LSBHZXJWYWRlcjJfY29tbWVudHNfbm4kY29tcG91bmQgJT4lIAogIGFzLmRhdGEuZnJhbWUoKSAlPiUgCiAgbXV0YXRlKGNvbXBvdW5kID0gbm9ybWFsaXplU2NvcmUoLiwgNDApKSU+JSBtdXRhdGUoYWxwaGEgPSA0MCkKYWxwaGFfOTAgPC0gR2VyVmFkZXIyX2NvbW1lbnRzX25uJGNvbXBvdW5kICU+JSAKICBhcy5kYXRhLmZyYW1lKCkgJT4lIAogIG11dGF0ZShjb21wb3VuZCA9IG5vcm1hbGl6ZVNjb3JlKC4sIDkwKSklPiUgbXV0YXRlKGFscGhhID0gOTApCmFscGhhXzIwMCA8LSBHZXJWYWRlcjJfY29tbWVudHNfbm4kY29tcG91bmQgJT4lIAogIGFzLmRhdGEuZnJhbWUoKSAlPiUgCiAgbXV0YXRlKGNvbXBvdW5kID0gbm9ybWFsaXplU2NvcmUoLiwgMjAwKSklPiUgbXV0YXRlKGFscGhhID0gMjAwKQphbHBoYV8zMCA8LSBHZXJWYWRlcjJfY29tbWVudHNfbm4kY29tcG91bmQgJT4lIAogIGFzLmRhdGEuZnJhbWUoKSAlPiUgCiAgbXV0YXRlKGNvbXBvdW5kID0gbm9ybWFsaXplU2NvcmUoLiwgMzApKSU+JSBtdXRhdGUoYWxwaGEgPSAzMCkKCmFscGhhX3Njb3JlcyA8LSByYmluZChhbHBoYV8xLCBhbHBoYV8xNSwgYWxwaGFfMzAsIGFscGhhXzQwLCBhbHBoYV85MCwgYWxwaGFfMjAwICkKCmFscGhhX3Njb3JlcyAlPiUgCiAgZ2dwbG90KCBhZXMoeD1jb21wb3VuZCwgY29sb3I9YWxwaGEsIGZpbGw9YWxwaGEpKSArCiAgICBnZW9tX2hpc3RvZ3JhbShhbHBoYT0uNywgYmlud2lkdGggPSAwLjA1KSArCiAgICBmYWNldF93cmFwKH5hbHBoYSkgKwogICAgZ2d0aXRsZSgiU2VudGltZW50dmVydGVpbHVuZyBkZXIgS29tbWVudGFyZSBmw7xyIEFscGhhLVdlcnRlIikgKwogICAgeGxhYigiU2VudGltZW50IikgKyB5bGFiKCIiKQoKYGBgCgoKIyMjIE5vcm1hbHZlcnRlaWx1bmcgZGVyIEtvbW1lbnRhci1TZW50aW1lbnRlCkRpZSBmb2xnZW5kZW4gU2hhcGlyby1XaWxrLVRlc3RzIGVyZ2ViZW4sIGRhc3MgZGllIEtvbW1lbnRhci1TZW50aW1lbnRlIHdlZGVyIHZvciBub2NoIG5hY2ggZGVyIEJlcsO8Y2tzaWNodGlndW5nIGRlciBTZW50aW1lbnQtVGVuZGVuemVuIGRlciBvYmpla3RpdmVuIFdvcnRlIGFubsOkaGVybmQgbm9ybWFsdmVydGVpbHQgaXN0LgoKYGBge3J9CnNoYXBpcm8udGVzdChHZXJWYWRlcjJfY29tbWVudHMkY29tcG91bmQgJT4lIHNhbXBsZSg1MDAwKSkKc2hhcGlyby50ZXN0KEdlclZhZGVyMl9jb21tZW50cyRjb21wb3VuZF9hbHQgJT4lIHNhbXBsZSg1MDAwKSkKYGBgCgoKCgojIyBTZW50aW1lbnRlIHBybyBCbG9nZWludHJhZwoKSGllciB3ZXJkZW4gZGllIGR1cmNoc2Nobml0dGxpY2hlbiBTZW50aW1lbnRlIGRlciBLb21tZW50YXJlIHBybyBCbG9nIGVycmVjaG5ldC4gCgpgYGB7cn0KR2VyVmFkZXJfcGVyX2Jsb2cgPC0gR2VyVmFkZXIyX2NvbW1lbnRzICU+JSAKICAjIGxhZGUgZGllIE1ldGFkYXRlbiBkZXIgQmxvZ2VpbnRyw6RnZQogIGlubmVyX2pvaW4oYmxvZ3MsIGJ5PWMoInByb2plY3RfaWQiLCAiYmxvZ19pZCIpKSAlPiUgCiAgZ3JvdXBfYnkocHJvamVjdF9pZCwgYmxvZ19pZCwgYXV0aG9yLCBuX2NvbW1lbnRzKSAlPiUgCiAgIyBlcnJlY2huZSBkaWUgU2VudGltZW50LU1pdHRlbHdlcnRlIHBybyBibG9nX2lkCiAgc3VtbWFyaXplKAogICAgU2VudGltZW50TWVhbiA9IG1lYW4oY29tcG91bmQsIG5hLnJtID0gVFJVRSksCiAgICBTZW50aW1lbnRNZWFuX2FsdCA9IG1lYW4oY29tcG91bmRfYWx0LCBuYS5ybSA9IFRSVUUpLAogICkgJT4lIAogICMgbGFkZSBkaWUgS2FtcGFnbmVuLU1ldGFkYXRlbiAoVGVpbG5laG1lcmFuemFobCkKICBpbm5lcl9qb2luKHByb2plY3RzICU+JSBzZWxlY3QocHJvamVjdF9pZCwgcGFydGljaXBhbnRzKSwgYnk9YygicHJvamVjdF9pZCIpKQoKCkdlclZhZGVyX3Blcl9ibG9nCmBgYAoKIyMjIFZlcnRlaWx1bmcgZGVyIEJsb2dlaW50cmFnLVNlbnRpbWVudGUKCkhpZXIgd2lyZCBkaWUgVmVydGVpbHVuZyBkZXIgZGVyIEJsb2dlaW50cmFnLVNlbnRpbWVudGUgdmlzdWFsaXNpZXJ0IHVuZCBhdWYgTm9ybWFsdmVydGVpbHVuZyBnZXRlc3RldC4gRGFzIGR1cmNoc2Nobml0dGxpY2ggU2VudGltZW50IGRlciBCbG9nZWludHJhZy1Lb21tZW50YXJlIGJldHLDpGd0IDAsNDkzLiAKCkRlciBTaGFwaXJvLVdpbGstVGVzdCB3ZWlzdCBuYWNoLCBkYXNzIGRpZSBCbG9nZWludHJhZy1TZW50aW1lbnRlIG5pY2h0IGFubsOkaGVybmQgbm9ybWFsdmVydGVpbHQgc2luZC4gCgpgYGB7cn0KIyBWZXJ0ZWlsdW5nIGRlciBCbG9nZWludHJhZy1TZW50aW1lbnRlCkdlclZhZGVyX3Blcl9ibG9nICU+JSAKICBnZ3Bsb3QoYWVzKHg9U2VudGltZW50TWVhbikpICsKICBnZW9tX2hpc3RvZ3JhbShiaW53aWR0aD0wLjAxKSArCiAgZ2VvbV92bGluZShhZXMoeGludGVyY2VwdD1tZWFuKFNlbnRpbWVudE1lYW4pKSwgbGluZXR5cGU9ImRhc2hlZCIsIGNvbG9yID0gInJlZCIpICsKICBnZ3RpdGxlKCJTZW50aW1lbnQtVmVydGVpbHVuZyBkZXIgQmxvZ2VpbnRyw6RnZSIpICsKICBsYWJzKHg9IlNlbnRpbWVudHdlcnQiLCAiTWVuZ2UiKQoKIyBUZXN0ZSBkaWUgVmVydGVpbHVuZyBkZXIgQmxvZ2VpbnRyYWctU2VudGltZW50ZSBhdWYgTm9ybWFsdmVydGVpbHVuZwpzaGFwaXJvLnRlc3QoR2VyVmFkZXJfcGVyX2Jsb2ckU2VudGltZW50TWVhbikKCiJNaXR0ZWx3ZXJ0IGRlciBkdXJoY3NjaG5pdHRsaWNoZW4gQmxvZ2VpbnRyYWctU2VudGltZW50ZSIKbWVhbihHZXJWYWRlcl9wZXJfYmxvZyRTZW50aW1lbnRNZWFuKQpgYGAKCgoKCgojIyBTZW50aW1lbnRlIHBybyBLYW1wYWduZSAoUHJvamVrdCkKCkF1Y2ggZsO8ciBkaWUgQW5hbHlzZSBkZXIgS2FtcGFnbmVuIHdlcmRlbiBkaWUgU2VudGltZW50ZSBkZXIgS29tbWVudGFyZSBuYWNoIEthbXBhZ25lbiBncnVwcGllcnQgdW5kIGlociBNaXR0ZWx3ZXJ0IGJlcmVjaG5ldC4KCmBgYHtyfQpHZXJWYWRlcl9wZXJfcHJvamVjdCA8LSBHZXJWYWRlcjJfY29tbWVudHMgJT4lIAogIGdyb3VwX2J5KHByb2plY3RfaWQpICU+JSAKICBzdW1tYXJpemUoCiAgICAjIGVycmVjaG5lIGRpZSBTZW50aW1lbnRzdW1tZSB1bmQgZGVuIFNlbnRpbWVudGR1cmNoc2Nobml0dAogICAgU2VudGltZW5TdW0gPSBzdW0oY29tcG91bmQpLAogICAgU2VudGltZW50TWVhbiA9IG1lYW4oY29tcG91bmQsIG5hLnJtID0gVFJVRSksCiAgICBTZW50aW1lbnRNZWFuX2FsdCA9IG1lYW4oY29tcG91bmRfYWx0LCBuYS5ybSA9IFRSVUUpLAogICAgIyBlcnJlY2huZSBkaWUgV29ydGFuemFobCBkZXIgS29tbWVudGFyZSBkZXIgS2FtcGFnbmUKICAgIHdvcmRDb3VudCA9IHN1bSh3b3JkQ291bnQpLAogICAgIyBlcnJlY2huZSBkaWUgQW56YWhsIGFuIEtvbW1lbnRhcmVuIGluIGVpbmVyIEthbXBhZ25lCiAgICBjb21tZW50Q291bnQgPSBuKCkKICAgICkgJT4lIAogICMgbGFkZSBkaWUgTWV0YWRhdGVuIGRlciBLYW1wYWduZW4sIEthbXBhZ25lbmVyZ2Vibmlzc2UgdW5kIEJsb2dlaW50csOkZ2UKICBpbm5lcl9qb2luKHByb2plY3RzLCBieT0icHJvamVjdF9pZCIpICU+JSAKICBpbm5lcl9qb2luKHJlc3VsdHMsIGJ5PSJwcm9qZWN0X2lkIikgJT4lIAogIGxlZnRfam9pbigKICAgIGJsb2dzICU+JSBncm91cF9ieShwcm9qZWN0X2lkLCBhdXRob3IpICU+JSBzdW1tYXJpemUobj1uKCkpICU+JSBzZWxlY3QocHJvamVjdF9pZCwgYXV0aG9yKSwKICAgIGJ5PSJwcm9qZWN0X2lkIgogICAgKSAlPiUgCiAgbGVmdF9qb2luKAogICAgYmxvZ3MgJT4lIGdyb3VwX2J5KHByb2plY3RfaWQpICU+JSBzdW1tYXJpemUoYmxvZ0NvdW50PW4oKSkgJT4lIHNlbGVjdChwcm9qZWN0X2lkLCBibG9nQ291bnQpLCAKICAgIGJ5PSJwcm9qZWN0X2lkIgogICAgKSAlPiUgCiAgIyBlcnJlY2huZSBkaWUgZHVyY2hzY2huaXR0bGljaGUgQW56YWhsIGFuIEtvbW1lbnRhcmVuIHBybyBLYW1wYWduZW50ZWlsbmVobWVyCiAgIyBuZW5uZSBkYXMgRXJnZWJuaXMgImVuZ2FnZW1lbnQiCiAgbXV0YXRlKGVuZ2FnZW1lbnQgPSBjb21tZW50Q291bnQgLyBwYXJ0aWNpcGFudHMpCgojIGVycmVjaG5lIGRpZSBMYXVmemVpdCBkZXMgUHJvamVrdHMKZ2V0UnVudGltZSA8LSBmdW5jdGlvbihzdGFydCxlbmQpewogIHN0YXJ0ID0gc3Ryc3BsaXQoc3RhcnQsICJbLl0iKQogIHN0YXJ0X2RheSA9IChzdGFydFtbMV1dWzFdKSAlPiUgYXMubnVtZXJpYygpIAogIHN0YXJ0X21vbnRoID0gKHN0YXJ0W1sxXV1bMl0pICU+JSBhcy5udW1lcmljKCkgCiAgc3RhcnRfeWVhciA9IChzdGFydFtbMV1dWzNdKSAlPiUgYXMubnVtZXJpYygpIAogIGVuZCA9IHN0cnNwbGl0KGVuZCwgIlsuXSIpCiAgZW5kX2RheSA9IChlbmRbWzFdXVsxXSkgJT4lIGFzLm51bWVyaWMoKSAKICBlbmRfbW9udGggPSAoZW5kW1sxXV1bMl0pICU+JSBhcy5udW1lcmljKCkgCiAgZW5kX3llYXIgPSAoZW5kW1sxXV1bM10pICU+JSBhcy5udW1lcmljKCkgCiAgcmV0dXJuICgoZW5kX2RheStlbmRfbW9udGgqMzArZW5kX3llYXIqMzY1KS0oc3RhcnRfZGF5K3N0YXJ0X21vbnRoKjMwK3N0YXJ0X3llYXIqMzY1KSkKfQpHZXJWYWRlcl9wZXJfcHJvamVjdCRydW50aW1lID0gbWFwcGx5KGdldFJ1bnRpbWUsIEdlclZhZGVyX3Blcl9wcm9qZWN0JHN0YXJ0X2RhdGUsIEdlclZhZGVyX3Blcl9wcm9qZWN0JGVuZF9kYXRlKQoKR2VyVmFkZXJfcGVyX3Byb2plY3QKc3VtbWFyeShHZXJWYWRlcl9wZXJfcHJvamVjdCkKYGBgCgojIyMgVmVydGVpbHVuZyBkZXIgS2FtcGFnbmVuLVNlbnRpbWVudGUKSGllciB3ZXJkZW4gZGllIFZlcnRlaWx1bmcgZGVyIEthbXBhZ25lbi1TZW50aW1lbnRlIHZpc3VhbGlzaWVydCB1bmQgYXVmIE5vcm1hbHZlcnRlaWx1bmcgZ2V0ZXN0ZXQuIERpZSBLYW1wYWduZW4gaGFiZW4gaW0gU2Nobml0dCBkdXJjaHNjaG5pdHRsaWNoZSBLb21tZW50YXItU2VudGltZW50ZSB2b24gMCw0ODMuIAoKRGVyIFNoYXBpcm8tV2lsay1UZXN0IGVyZ2lidCwgZGFzcyBkaWUgZHVyY2hzY2huaXR0bGljaGVuIEtvbW1lbnRhci1TZW50aW1lbnRlIHBybyBLYW1wYWduZSBhbm7DpGhlcm5kIG5vcm1hbHZlcnRlaWx0IHNpbmQuCgpgYGB7cn0KR2VyVmFkZXJfcGVyX3Byb2plY3QgJT4lIAogIGdncGxvdChhZXMoeD1TZW50aW1lbnRNZWFuKSkgKwogIGdlb21faGlzdG9ncmFtKGJpbndpZHRoPTAuMDA1KSArCiAgZ2VvbV92bGluZShhZXMoeGludGVyY2VwdD1tZWFuKFNlbnRpbWVudE1lYW4pKSwgbGluZXR5cGU9ImRhc2hlZCIsIGNvbG9yID0gInJlZCIpICsKICBnZ3RpdGxlKCJTZW50aW1lbnQtVmVydGVpbHVuZyBkZXIgUHJvamVrdGUiKSArCiAgbGFicyh4PSJTZW50aW1lbnR3ZXJ0IiwgIk1lbmdlIikKCiJEdXJjaHNjaG5pdHRsaWNoZSBLYW1wYWduZW4tU2VudGltZW50ZSIKbWVhbihHZXJWYWRlcl9wZXJfcHJvamVjdCRTZW50aW1lbnRNZWFuKQoKIk5lZ2F0aXZzdGVyIEthbXBhZ25lbi1TZW50aW1lbnQtTWl0dGVsd2VydCIKbWluKEdlclZhZGVyX3Blcl9wcm9qZWN0JFNlbnRpbWVudE1lYW4pCgojIFRlc3RlIGRpZSBLYW1wYWduZW4tU2VudGltZW50ZSBhdWYgTm9ybWFsdmVydGVpbHVuZwpzaGFwaXJvLnRlc3QoR2VyVmFkZXJfcGVyX3Byb2plY3QkU2VudGltZW50TWVhbikKYGBgCgoKCiMjIyBLb3JyZWxhdGlvbmVuIHp3aXNjaGVuIEthbXBhZ25lbmVpZ2Vuc2NoYWZ0ZW4gdW5kIGlocmVuIEVyZ2Vibmlzc2VuCgpJbSBmb2xnZW5kZW4gd2VyZGVuIGRpZSBFcmdlYm5pc3NlIGRlciBLYW1wYWduZW4sIGFsc28gZGVyIGVya2FubnRlbiBTZW50aW1lbnQsIGRlbiBkdXJjaHNjaG5pdHRsaWNoZW4gS3VuZGVuYmV3ZXJ0dW5nZW4gdW5kIGRlbiBkdXJjaHNjaG5pdHRsaWNoZW4gV2VpdGVyZW1wZmVobHVuZ3NxdW90ZW4sIGF1ZiBLb3JyZWxhdGlvbiBtaXRlaW5hbmRlciB1bmQgbWl0IGFuZGVyZW4gVmFyaWFibGVuLCBuw6RtbGljaCBkZXIgQW56YWhsIGFuIEJsZ29laW50csOkZ2VuIHVuZCBUZWlsbmVobWVybiBwcm8gS2FtcGFnbmUsIGRlciBMYXVmemVpdCBqZWRlciBLYW1wYWduZSB1bmQgZGVtIEVuZ2FnZW1lbnQsIGRhc3MgZGllIFRlaWxuZWhtZXIgaW0gU2Nobml0dCB6ZWlndGVuLiAKCmBgYHtyfQpHZXJWYWRlcl9wZXJfcHJvamVjdCAlPiUgCiAgc2VsZWN0KAogICAgU2VudGltZW50TWVhbiwgCiAgICB3ZWl0ZXJlbXBmZWhsdW5nc3F1b3RlLCAKICAgIHJhdGluZ192YWx1ZSwgCiAgICBibG9nQ291bnQsCiAgICBwYXJ0aWNpcGFudHMsCiAgICBydW50aW1lLAogICAgZW5nYWdlbWVudAogICAgKSAlPiUgCiAgcGFpcnMucGFuZWxzKCkKYGBgCgpJbSBmb2xnZW5kZW4gd2VyZGVuIGRpZSBlbnRkZWNrdGVuIEtvcnJlbGF0aW9uZW4gYXVmIFNpZ25pZmlrYW56IGdldGVzdGV0LgoKRXMgZ2lidCBlaW4gc2lnbmlmaWthbnRlLCB3ZW5uIGF1Y2ggbmljaHQgc3RhcmtlLCBLb3JyZWxhdGlvbiB6d2lzY2hlbiBkZW4gZHVyY2ggR2VyVmFkZXIyIGVya2FubnRlbiwgZHVyY2hzY2huaXR0bGljaGVuIFNlbnRpbWVudGVuIGRlciBQcm9qZWt0ZSB1bmQgaWhyZW4gV2VpdGVyZW1wZmVobHVuZ3NyYXRlbiAoMCwyMCkgdW5kIEJld2VydHVuZ2VuICgwLDMzKS4KCkViZW5zbyBnaWJ0IGVzIGVpbmUgc2lnbmlmaWthbnRlLCBzY2h3YWNoIG5lZ2F0aXZlIEtvcnJlbGF0aW9uICgtMCwyNCkgendpc2NoZW4gZGVtIFNlbnRpbWVudCBkZXIgS29tbWVudGFyZSBwcm8gS2FtcGFnbmUgdW5kIGRlciBBbnphaGwgYW4gQmxvZ2VpbnRyw6RnZW4gw7xiZXIgZGllIEthbXBhZ25lbmxhdWZ6ZWl0LiAKCgpgYGB7cn0KY29yLnRlc3QoR2VyVmFkZXJfcGVyX3Byb2plY3QkU2VudGltZW50TWVhbiwgR2VyVmFkZXJfcGVyX3Byb2plY3Qkd2VpdGVyZW1wZmVobHVuZ3NxdW90ZSkKY29yLnRlc3QoR2VyVmFkZXJfcGVyX3Byb2plY3QkU2VudGltZW50TWVhbiwgR2VyVmFkZXJfcGVyX3Byb2plY3QkcmF0aW5nX3ZhbHVlKQpjb3IudGVzdChHZXJWYWRlcl9wZXJfcHJvamVjdCRTZW50aW1lbnRNZWFuLCBHZXJWYWRlcl9wZXJfcHJvamVjdCRibG9nQ291bnQpCmNvci50ZXN0KEdlclZhZGVyX3Blcl9wcm9qZWN0JFNlbnRpbWVudE1lYW4sIEdlclZhZGVyX3Blcl9wcm9qZWN0JHBhcnRpY2lwYW50cykKY29yLnRlc3QoR2VyVmFkZXJfcGVyX3Byb2plY3QkU2VudGltZW50TWVhbiwgR2VyVmFkZXJfcGVyX3Byb2plY3QkcnVudGltZSkKY29yLnRlc3QoR2VyVmFkZXJfcGVyX3Byb2plY3QkU2VudGltZW50TWVhbiwgR2VyVmFkZXJfcGVyX3Byb2plY3QkZW5nYWdlbWVudCkKYGBgCgpOdW4gd2VyZGVuIGRpZSBhbmdlYmxpY2ggc2lnbmlmaWthbnRlbiBLb3JyZWxhdGlvbmVuIGdlbmF1ZXIgdmlzdWFsaXNpZXJ0LgoKYGBge3J9CkdlclZhZGVyX3Blcl9wcm9qZWN0ICU+JSAKICBnZ3Bsb3QoYWVzKHdlaXRlcmVtcGZlaGx1bmdzcXVvdGUsIFNlbnRpbWVudE1lYW4pKSArCiAgZ2VvbV9qaXR0ZXIoKSArCiAgZ2d0aXRsZSgiS29ycmVsYXRpb24gendpc2NoZW4gU2VudGltZW50IHBybyBQcm9qZWt0IHVuZCBXZWl0ZXJlbXBmZWhsdW5nc3JhdGUiKSsKICB5bGFiKCJkdXJjaHNjaG4uIFNlbnRpbWVudCBwcm8gUHJvamVrdCIpICsgeGxhYigiZHVyY2hzY2huLiBXZWl0ZXJlbXBmZWhsdW5nc3JhdGUiKQogIApHZXJWYWRlcl9wZXJfcHJvamVjdCAlPiUgCiAgZ2dwbG90KGFlcyhyYXRpbmdfdmFsdWUsIFNlbnRpbWVudE1lYW4pKSArCiAgZ2VvbV9qaXR0ZXIoKSArCiAgZ2d0aXRsZSgiS29ycmVsYXRpb24gendpc2NoZW4gU2VudGltZW50IHBybyBQcm9qZWt0IHVuZCAgS3VuZGVuYmV3ZXJ0dW5nIikrCiAgeWxhYigiZHVyY2hzY2huLiBTZW50aW1lbnQgcHJvIFByb2pla3QiKSArIHhsYWIoImR1cmNoc2Nobi4gS3VuZGVuYmV3ZXJ0dW5nIikKICAKR2VyVmFkZXJfcGVyX3Byb2plY3QgJT4lIAogIGdncGxvdChhZXMoYmxvZ0NvdW50LCBTZW50aW1lbnRNZWFuKSkgKwogIGdlb21faml0dGVyKCkgKwogIGdndGl0bGUoIktvcnJlbGF0aW9uIHp3aXNjaGVuIFNlbnRpbWVudCBwcm8gUHJvamVrdCB1bmQgQW56YWhsIGFuIEJsb2dlaW50csOkZ2VuIikrCiAgeWxhYigiZHVyY2hzY2huLiBTZW50aW1lbnQgcHJvIFByb2pla3QiKSArIHhsYWIoIkJsb2dlaW50csOkZ2UiKQpgYGAKCgoKCgoKCiMjIEthbXBhZ25lbnJlc3VsdGF0ZSBwcm8gRG9tw6RuZSAoY2F0ZWdvcnkpCkltIGZvbGdlbmRlbiB3ZXJkZW4gcHJvIERvbcOkbmUgZGllIGR1cmNoc2Nobml0dGxpY2hlbiBTZW50aW1lbnRlLCBUZWlsbmVobWVyYmV3ZXJ0dW5nZW4sIFdlaXRlcmVtcGZlaGx1bmdzcXVvdGVuIHVuZCBkaWUgVmFyaWFueiBkZXIgU2VudGltZW50ZSBiZXJlY2huZXQuCmBgYHtyfQoiRG9tw6RuZW4gZGVyIEthbXBhZ25lbiIKcHJvamVjdHMkY2F0ZWdvcnkgJT4lIHVuaXF1ZSgpCgpHZXJWYWRlcjJfcGVyX2NhdGVnb3J5IDwtIEdlclZhZGVyMl9jb21tZW50cyAlPiUgCiAgIyBsYWRlIE1ldGFkYXRlbiBkZXIgS2FtcGFnbmVuIHVuZCBpaHJlciBFcmdlYm5pc3NlCiAgaW5uZXJfam9pbihwcm9qZWN0cywgYnk9InByb2plY3RfaWQiKSAlPiUgCiAgaW5uZXJfam9pbihyZXN1bHRzLCBieT0icHJvamVjdF9pZCIpICU+JSAKICBncm91cF9ieShjYXRlZ29yeSkgJT4lIAogICMgU3RhdGlzdGlrZW5wcm8gRG9tw6RuZQogICBzdW1tYXJpemUoCiAgICAgIyBTZW50aW1lbnQtTWl0dGVsd2VydAogICAgU2VudGltZW50TWVhbiA9IG1lYW4oY29tcG91bmQsIG5hLnJtID0gVFJVRSksCiAgICAjIEtvbW1lbnRhcmFuemFobAogICAgY29tbWVudF9jb3VudCA9IG4oKSwKICAgICMgZHVyY2hzY2huaXR0bGljaGUgVGVpbG5laG1lcmJld2VydHVuZwogICAgUmF0aW5nTWVhbiA9IG1lYW4ocmF0aW5nX3ZhbHVlLCBuYS5ybT1UUlVFKSwKICAgICMgZHVyY2hzY2huaXR0bGljaGUgV2VpdGVyZW1wZmVobHVuZ3NyYXRlCiAgICBXZWl0ZXJlbXBmZWhsdW5nc3F1b3RlTWVhbiA9IG1lYW4od2VpdGVyZW1wZmVobHVuZ3NxdW90ZSwgbmEucm09VFJVRSksCiAgICAjIFZhcmlhbnogZGVyIFNlbnRpbWVudGUKICAgIHZhcmlhbmNlID0gdmFyKGNvbXBvdW5kLCBuYS5ybT1UUlVFKQogICAgKSAlPiUgCiAgYXJyYW5nZShkZXNjKFNlbnRpbWVudE1lYW4pKQoKR2VyVmFkZXIyX3Blcl9jYXRlZ29yeQpHZXJWYWRlcjJfcGVyX2NhdGVnb3J5JFNlbnRpbWVudE1lYW4gJT4lIGJhcnBsb3QobGVnZW5kPUdlclZhZGVyMl9wZXJfY2F0ZWdvcnkkY2F0ZWdvcnkpCgpgYGAKCgoKCgoKIyMgQW5hbHlzZSBkZXIgS2FtcGFnbmVubWFuYWdlcgoKSGllciB3aXJkIGRhcyBqZXdlaWxpZ2UgRW5nYWdlbWVudCBkZXIgVGVpbG5laG1lciBwcm8gS2FtcGFnbmVubWFuYWdlciBnZXplaWd0LiAKCmBgYHtyfQpHZXJWYWRlcl9wZXJfcHJvamVjdCAlPiUgCiAgc2VsZWN0KHByb2plY3RfaWQsIGF1dGhvciwgZW5nYWdlbWVudCkgJT4lIAogIGFycmFuZ2UoZGVzYyhlbmdhZ2VtZW50KSkKYGBgCgpIaWVyIHdpcmQgZWluIERhdGVuc2F0eiBtaXQgZGVuIGR1cmNoc2Nobml0dGxpY2hlbiBLb21tZW50YXItU2VudGltZW50ZW4sIFRlaWxuZWhtZXJiZXdlcnR1bmdlbiB1bmQgV2VpdGVyZW1wZmVobHVuZ3NxdW90ZW4gcHJvIEthbXBhZ25lbm1hbmFnZXIsIHNvd2llIGRlciBBbnphaGwgdmVyd2FsdGV0ZXIgS2FtcGFnbmVuIHVuZCBkZW0gYW5nZXJlZ3RlbiBFbmdhZ2VtZW50LCBhbHNvIGRlciBkdXJjaHNjaG5pdHRsaWNoZW4gQW56YWhsIGFuIEtvbW1lbnRhcmVuLCBlcnJlY2huZXQuCgpgYGB7cn0KR2VyVmFkZXJfcHJvamVjdHNfcGVyX2F1dGhvciA8LSBHZXJWYWRlcl9wZXJfcHJvamVjdCAlPiUgCiAgZ3JvdXBfYnkoYXV0aG9yKSAlPiUgCiAgc3VtbWFyaXNlKAogICAgU2VudGltZW50TWVhbiA9IG1lYW4oU2VudGltZW50TWVhbiwgbmEucm0gPSBUUlVFKSwKICAgIHdlaXRlcmVtcGZlaGx1bmdzcXVvdGUgPSBtZWFuKHdlaXRlcmVtcGZlaGx1bmdzcXVvdGUsIG5hLnJtID0gVFJVRSksCiAgICByYXRpbmdfdmFsdWUgPSBtZWFuKHJhdGluZ192YWx1ZSwgbmEucm0gPSBUUlVFKSwKICAgIG5fcHJvamVjdHMgPSBuKCksCiAgICBlbmdhZ2VtZW50ID0gbWVhbihjb21tZW50Q291bnQgLyBwYXJ0aWNpcGFudHMsIG5hLnJtID0gVFJVRSkKICApICU+JSAKICBhcnJhbmdlKGRlc2MoU2VudGltZW50TWVhbikpCkdlclZhZGVyX3Byb2plY3RzX3Blcl9hdXRob3IKYGBgCgojIyMgS29ycmVsYXRpb25lbiBkZXIgRXJnZWJuaXNzZSBwcm8gS2FtcGFnbmVubWFuYWdlcgpIaWVyIHdlcmRlbiBkaWUgRXJmb2xnc21ldHJpa2VuIHBybyBLYW1wYWduZW5tYW5hZ2VyIGF1ZiBLb3JyZWxhdGlvbmVuIHVudGVyc3VjaHQuCgpgYGB7cn0KR2VyVmFkZXJfcHJvamVjdHNfcGVyX2F1dGhvciAlPiUgCiAgc2VsZWN0KAogICAgU2VudGltZW50TWVhbiwgCiAgICB3ZWl0ZXJlbXBmZWhsdW5nc3F1b3RlLCAKICAgIHJhdGluZ192YWx1ZSwgCiAgICBuX3Byb2plY3RzLAogICAgZW5nYWdlbWVudAogICAgKSAlPiUgCiAgcGFpcnMucGFuZWxzKCkKYGBgCkRpZSBLb3JyZWxhdGlvbmVuIHNpbmQgYWxsZXNhbXQgbmljaHQgc2lnbmlmaWthbnQuIERhcyBrw7ZubnRlIGF1Y2ggZGFyYW4gbGllZ2VuLCBkYXNzIG51ciBzZWhyIHdlbmlnZSB2ZXJzY2hpZWRlbmUgS2FtcGFnbmVubWFuYWdlciBpbiBkZW4gRGF0ZW4gdm9ybGllZ2VuLCB2aWVsbGVpY2h0IGVyZ2ViZW4gc2ljaCBpbSBncm/Dn2VuIEdhbnplbiBzaWduaWZpa2FudGVyZSBUcmVuZHMuCgpgYGB7cn0KY29yLnRlc3QoR2VyVmFkZXJfcHJvamVjdHNfcGVyX2F1dGhvciRTZW50aW1lbnRNZWFuLCBHZXJWYWRlcl9wcm9qZWN0c19wZXJfYXV0aG9yJHdlaXRlcmVtcGZlaGx1bmdzcXVvdGUpCmNvci50ZXN0KEdlclZhZGVyX3Byb2plY3RzX3Blcl9hdXRob3IkU2VudGltZW50TWVhbiwgR2VyVmFkZXJfcHJvamVjdHNfcGVyX2F1dGhvciRyYXRpbmdfdmFsdWUpCmNvci50ZXN0KEdlclZhZGVyX3Byb2plY3RzX3Blcl9hdXRob3IkU2VudGltZW50TWVhbiwgR2VyVmFkZXJfcHJvamVjdHNfcGVyX2F1dGhvciRuX3Byb2plY3RzKQpjb3IudGVzdChHZXJWYWRlcl9wcm9qZWN0c19wZXJfYXV0aG9yJHJhdGluZ192YWx1ZSwgR2VyVmFkZXJfcHJvamVjdHNfcGVyX2F1dGhvciRuX3Byb2plY3RzKQpjb3IudGVzdChHZXJWYWRlcl9wcm9qZWN0c19wZXJfYXV0aG9yJHdlaXRlcmVtcGZlaGx1bmdzcXVvdGUsIEdlclZhZGVyX3Byb2plY3RzX3Blcl9hdXRob3IkZW5nYWdlbWVudCkKYGBgCgoKCgoKCgoKCgojIyBLYW1wYWduZW4tU2VudGltZW50ZSDDvGJlciBpaHJlIExhdWZ6ZWl0CkFscyBuw6RjaHN0ZXMgd2VyZGVuIGRpZSBLb21tZW50YXItU2VudGltZW50ZSBkZXIgQmxvZ2VpbnRyw6RnZSBqZWRlciBLYW1wYWduZSB2aXN1YWxpc2llcnQsIHVtIFNlbnRpbWVudC1UcmVuZHMgw7xiZXIgZGllIEthbXBhZ25lbmVudHdpY2tsdW5nIGVya2VubmJhciB6dSBtYWNoZW4uCgoKYGBge3J9CiMgRnVua3Rpb24genVyIFZpc3VhbGlzaWVydW5nIHZvbiBTZW50aW1lbnQtRW50d2lja2x1bmdlbiBlaW5lciBLYW1wYWduZQoKU2VudGltZW50RW50d2lja2x1bmcgPC0gZnVuY3Rpb24oR2VyVmFkZXJfcGVyX2Jsb2csIHByb2plY3RfaWRzPWMoMToxMDAwMDAwMDApLCBzaG93TGVnZW5kPVRSVUUsIG9wYWNpdHk9MSwgcG9pbnRzPVRSVUUsIHRpdGxlPSIiKSB7CiAgR2VyVmFkZXJfcGVyX2Jsb2cgJT4lIAogICAgbXV0YXRlKAogICAgICBwcm9qZWN0X2lkID0gZmFjdG9yKHByb2plY3RfaWQpLAogICAgKSAlPiUgCiAgICBmaWx0ZXIocHJvamVjdF9pZCAlaW4lIHByb2plY3RfaWRzKSAlPiUgCiAgICBnZ3Bsb3QoYWVzKGJsb2dfaWRfYWx0LCBTZW50aW1lbnRNZWFuLCBjb2xvcj1wcm9qZWN0X2lkKSkgKwogICAgICBnZW9tX2xpbmUoYWxwaGE9b3BhY2l0eSwgc2hvdy5sZWdlbmQgPSBzaG93TGVnZW5kKSArCiAgICAgIGdlb21fcG9pbnQoc2hvdy5sZWdlbmQgPSBzaG93TGVnZW5kLCBhbHBoYT1wb2ludHMpICsKICAgICAgZ2d0aXRsZShnbHVlKCJTZW50aW1lbnQtRW50d2lja2x1bmcgZsO8ciBLYW1wYWduZShuKSB7dGl0bGV9IikpICsKICAgICAgeGxhYigiQmxvZyBJRCIpICsKICAgICAgZ2VvbV9wb2ludCgpICU+JSAKICAgIHByaW50KCkKfQpgYGAKCgpgYGB7cn0KIyBLYW1wYWduZSAxNwpTZW50aW1lbnRFbnR3aWNrbHVuZyhHZXJWYWRlcl9wZXJfYmxvZywgcHJvamVjdF9pZHM9MTcsIHRpdGxlPSIjMTciKQojIEFsbGUgS2FtcGFnbmVuIG1pdCBJZHMgendpc2NoZW4gMSB1bmQgMzAKU2VudGltZW50RW50d2lja2x1bmcoR2VyVmFkZXJfcGVyX2Jsb2cscHJvamVjdF9pZHM9IGMoMTozMCksIFRSVUUsIHRpdGxlPSIiKQojIEFsbGUgS2FtcGFnbmVuIG1pdCBJZHMgendpc2NoZW4gMSB1bmQgMzAwMApTZW50aW1lbnRFbnR3aWNrbHVuZyhHZXJWYWRlcl9wZXJfYmxvZywgcHJvamVjdF9pZHM9YygxOjMwMCksIEZBTFNFLCAwLjIsIEZBTFNFKQpgYGAKCgoKCiMjIEFuYWx5c2Ugdm9uIGJlc3RpbW10ZW4gS2FtcGFnbmVubWFuYWdlcm4gdW5kIGlocmVuIEthbXBhZ25lbgpIaWVyIHdlcmRlbiBkaWUgS2FtcGFnbmVubWFuYWdlciAibGVzb2Z5IiB1bmQgaW5zYmVzb25kZXJlICJuZWxsaXNhIiBnZW5hdWVyIHVudGVyIGRpZSBMdXBlIGdlbm9tbWVuLgpgYGB7cn0KCiMgUHJvamVjdHMgZm9yIGNhbXBhaWduIG1hbmFnZXIgbGVzb2Z5ClNlbnRpbWVudEVudHdpY2tsdW5nKEdlclZhZGVyX3Blcl9ibG9nICU+JSBmaWx0ZXIoYXV0aG9yPT0idHJpbmlkaSIpLCB0aXRsZT0iS2FtcGFnbmVubWFuYWdlcjogdHJpbmlkaSIpCiMgUHJvamVjdHMgZm9yIGNhbXBhaWduIG1hbmFnZXIgbmVsbGlzYQpTZW50aW1lbnRFbnR3aWNrbHVuZyhHZXJWYWRlcl9wZXJfYmxvZyAlPiUgZmlsdGVyKGF1dGhvcj09Im5lbGxpc2EiKSwgdGl0bGU9IkthbXBhZ25lbm1hbmFnZXI6IG5lbGxpc2EiKQoKYGBgCgoKCgoKCiMjIyBEZXRhaWxhbmFseXNlOiBLYW1wYWduZW5tYW5hZ2VyICJOZWxsaXNhIiB1bmQgaWhyZSBLYW1wYWduZSAjMTk4CmBgYHtyfQojIERhdGVuc2F0eiBmw7xyIG5lbGxpc2EKbmVsbGlzYSA8LSBHZXJWYWRlcjJfY29tbWVudHMgJT4lIAogIGlubmVyX2pvaW4oCiAgICBibG9ncyAlPiUgc2VsZWN0KHByb2plY3RfaWQsIGF1dGhvciksIAogICAgYnk9InByb2plY3RfaWQiKSAlPiUgCiAgZGlzdGluY3QoKSAlPiUgCiAgcmVuYW1lKGNhbXBhaWduX21hbmFnZXIgPSBhdXRob3IpICU+JSAKICBmaWx0ZXIoY2FtcGFpZ25fbWFuYWdlciA9PSAibmVsbGlzYSIpCgpuZWxsaXNhCgpgYGAKCkRpZSBLYW1wYWduZSAxOTggaGF0LCB3aWUgb2JlbiBlcnNpY2h0bGljaCwgZWluIFNlbnRpbWVudHRpZWYgYmVpIGRlbiBlcnN0ZW4gQmxvZ2VpbnRyw6RnZW4uIERhcyB3aXJkIGhpZXIgZ2VuYXVlciB1bnRlcnN1Y2h0LgoKCmBgYHtyfQojIERhdGVuc2F0eiBkZXIgS2FtcGFnbmUgIzE5OApuZWxsaXNhXzE5OCA8LSBHZXJWYWRlcjJfY29tbWVudHMgJT4lIAogIGZpbHRlcihwcm9qZWN0X2lkID09IDE5OCkKCm5lbGxpc2FfMTk4JGNvbXBvdW5kICU+JSBib3hwbG90KGhvcml6b250YWw9VFJVRSwgbWFpbj0iQm94cGxvdCBTZW50aW1lbnRlIGRlciBLYW1wYWduZSAxOTgiKQphYmxpbmUodiA9IG1lYW4oR2VyVmFkZXIyX2NvbW1lbnRzJGNvbXBvdW5kKSwgY29sPSJyZWQiLCBsd2Q9MywgbHR5PTIpCgpuZWxsaXNhXzE5OF9wZXJfYmxvZyA8LSBuZWxsaXNhXzE5OCAlPiUgCiAgZ3JvdXBfYnkoYmxvZ19pZCkgJT4lIAogIHN1bW1hcmlzZSgKICAgIFNlbnRpbWVudE1lYW4gPSBtZWFuKGNvbXBvdW5kKSwKICAgIGNvbW1lbnRfY291bnQgPSBuKCkKICApCgpuZWxsaXNhXzE5OF9wZXJfYmxvZyAlPiUgCiAgZ2dwbG90KGFlcyh4PWJsb2dfaWQsIHk9U2VudGltZW50TWVhbiwgY29sPWNvbW1lbnRfY291bnQpKSArCiAgZ2VvbV9saW5lKCkgKyBnZW9tX3BvaW50KCkgKwogIGdndGl0bGUoIlNlbnRpbWVudC1NaXR0ZWx3ZXJ0IGbDvHIgS2FtcGFnbmUgMTk4IikgKwogIHhsYWIoIkJsb2cgSUQiKQoKYGBgCgojIyMjIFZlcmdsZWljaGUgZGllIEFuemFobCBuZWdhdGl2ZXIgS29tbWVudGFyZSBtaXQgZGVtIGR1cmNoc2Nobml0dGxpY2hlbiBLb21tZW50YXJzZW50aW1lbnQgcHJvIEJsb2dlaW50cmFnIMO8YmVyIGRpZSBLYW1wYWduZW5lbnR3aWNrbHVuZwoKRGllIGZvbGdlbmRlIEdyYWZpayB6ZWlndCwgZGFzcyBlcyB3w6RocmVuZCBkZW0gVGllZiBkZXIgZHVyY2hzY2huaXR0bGljaGVuIFNlbnRpbWVudGUgKHTDvHJraXMpIGRlciBlcnN0ZW4gQmxvZ2VpbnRyw6RnZSBhdWNoIHJlbGF0aXYgdmllbGUgbmVnYXRpdmUgS29tbWVudGFyZSAob3JhbmdlLCBzdHJpY2hsaWVydCkgZ2FiLgoKYGBge3J9CgojIGVyc3RlbGxlIGVpbmVuIERhdGVuc2F0eiBkZXIgQW56YWhsIGFuIEtvbW1lbnRhcmVuIAojIGRlcmVuIFNlbnRpbWVudGUga2xlaW5lciBhbHMgMCwgYWxzbyBuZWdhdGl2LCBzaW5kCm5lbGxpc2FfMTk4X25lZ2F0aXZlIDwtIG5lbGxpc2FfMTk4ICU+JSAKICBncm91cF9ieShibG9nX2lkKSAlPiUgCiAgbXV0YXRlKAogICAgU2VudGltZW50TWVhbj1tZWFuKGNvbXBvdW5kLCBuYS5ybT1UUlVFKSwKICAgIGlzX3VuZGVyX21pbiA9IGNvbXBvdW5kIDwgMAogICAgKSAlPiUgCiAgZ3JvdXBfYnkoYmxvZ19pZCwgU2VudGltZW50TWVhbikgJT4lIAogIHN1bW1hcmlzZSggbl9uZWdhdGl2ZT1zdW0oaXNfdW5kZXJfbWluKSApIAoKCmdncGxvdCgpICsKICBnZW9tX2xpbmUobWFwcGluZyA9IGFlcyh4PW5lbGxpc2FfMTk4X3Blcl9ibG9nJGJsb2dfaWQsIHk9bmVsbGlzYV8xOThfcGVyX2Jsb2ckU2VudGltZW50TWVhbiksIGNvbD0iY3lhbjMiKSArCiAgZ2VvbV9saW5lKG1hcHBpbmcgPSBhZXMoeD1uZWxsaXNhXzE5OF9uZWdhdGl2ZSRibG9nX2lkLCB5PShuZWxsaXNhXzE5OF9uZWdhdGl2ZSRuX25lZ2F0aXZlKzMwKS84NSksIGNvbD0iZGFya29yYW5nZSIsIGxpbmV0eXBlID0gImRhc2hlZCIpICsKICBzY2FsZV95X2NvbnRpbnVvdXMobmFtZSA9ICJTZW50aW1lbnRNZWFuIiwKICAgICAgICAgICAgICAgICAgICAgc2VjLmF4aXMgPSBzZWNfYXhpcyh+Lio4NS0zMCwgbmFtZSA9ICJBbnphaGwgQXVzcmVpw59lci1Lb21tZW50YXJlIikpICsKICB4bGFiKCJCbG9nIElEIikgICsKICB0aGVtZSgKICAgIGF4aXMudGl0bGUueS5sZWZ0PWVsZW1lbnRfdGV4dChjb2xvcj0iY3lhbjMiKSwKICAgIGF4aXMudGV4dC55LmxlZnQ9ZWxlbWVudF90ZXh0KGNvbG9yPSJjeWFuMyIpLAogICAgYXhpcy50aXRsZS55LnJpZ2h0PWVsZW1lbnRfdGV4dChjb2xvcj0iZGFya29yYW5nZSIpLAogICAgYXhpcy50ZXh0LnkucmlnaHQ9ZWxlbWVudF90ZXh0KGNvbG9yPSJkYXJrb3JhbmdlIikKICApCmBgYAoKIyMjIyBWZXJnbGVpY2hlIGRpZSBBbnphaGwgc2VociBwb3NpdGl2ZXIgS29tbWVudGFyZSBtaXQgZGVtIGR1cmNoc2Nobml0dGxpY2hlbiBLb21tZW50YXJzZW50aW1lbnQgcHJvIEJsb2dlaW50cmFnIMO8YmVyIGRpZSBLYW1wYWduZW5lbnR3aWNrbHVuZwoKRGllIGZvbGdlbmRlIEdyYWZpayB6ZWlndCwgZGFzcyBlcyB3w6RocmVuZCBkZW0gVGllZiBkZXIgZHVyY2hzY2huaXR0bGljaGVuIFNlbnRpbWVudGUgKHTDvHJraXMpIGF1Y2ggcmVsYXRpdiB3ZW5pZ2VyIHNlaHIgcG9zaXRpdmUgS29tbWVudGFyZSAocGluaywgc3RyaWNobGllcnQpIGdhYi4KCmBgYHtyfQojIFVudGVyZXIgR3Jlbnp3ZXJ0IGRlcyB2aWVydGVuIFF1YXJ0aWxzIGRlciBTZW50aW1lbnRlIGFsbGVyIEthbXBhZ25lbgoocTMgPSBzdW1tYXJ5KEdlclZhZGVyMl9jb21tZW50cyRjb21wb3VuZClbNV0pCgoKIyBlcnN0ZWxsZSBlaW5lbiBEYXRlbnNhdHogZGVyIEFuemFobCBhbiBLb21tZW50YXJlbiAKIyBkZXJlbiBTZW50aW1lbnRlIGltIHZpZXJ0ZW4gUXVhcnRpbCBsaWVnZSwgYWxzbyBzZWhyIHBvc2l0aXYgc2luZApuZWxsaXNhXzE5OF9wb3NpdGl2ZSA8LSBuZWxsaXNhXzE5OCAlPiUgCiAgZ3JvdXBfYnkoYmxvZ19pZCkgJT4lIAogIG11dGF0ZSgKICAgIFNlbnRpbWVudE1lYW49bWVhbihjb21wb3VuZCwgbmEucm09VFJVRSksCiAgICBpc192ZXJ5X3Bvc2l0aXZlID0gY29tcG91bmQgPiBxMwogICAgKSAlPiUgCiAgZ3JvdXBfYnkoYmxvZ19pZCwgU2VudGltZW50TWVhbikgJT4lIAogIHN1bW1hcmlzZSggbl92ZXJ5X3Bvc2l0aXZlPXN1bShpc192ZXJ5X3Bvc2l0aXZlKSApIAoKCmdncGxvdCgpICsKICBnZW9tX2xpbmUobWFwcGluZyA9IGFlcyh4PW5lbGxpc2FfMTk4X3Blcl9ibG9nJGJsb2dfaWQsIHk9bmVsbGlzYV8xOThfcGVyX2Jsb2ckU2VudGltZW50TWVhbiksIGNvbD0iY3lhbjMiKSArCiAgZ2VvbV9saW5lKG1hcHBpbmcgPSBhZXMoeD1uZWxsaXNhXzE5OF9wb3NpdGl2ZSRibG9nX2lkLCB5PShuZWxsaXNhXzE5OF9wb3NpdGl2ZSRuX3ZlcnlfcG9zaXRpdmUrNTAwKS8xNTAwKSwgY29sPSJ2aW9sZXRyZWQxIiwgbGluZXR5cGUgPSAiZGFzaGVkIikgKwogIHNjYWxlX3lfY29udGludW91cyhuYW1lID0gIlNlbnRpbWVudE1lYW4iLAogICAgICAgICAgICAgICAgICAgICBzZWMuYXhpcyA9IHNlY19heGlzKH4uKjE1MDAtNTAwLCBuYW1lID0gIkFuemFobCBLb21tZW50YXJlIFNlbnRpbWVudCBpbSB2aWVydGVuIFF1YXJ0aWwiKSkgKwogIHhsYWIoIkJsb2cgSUQiKSAgKwogIHRoZW1lKAogICAgYXhpcy50aXRsZS55LmxlZnQ9ZWxlbWVudF90ZXh0KGNvbG9yPSJjeWFuMyIpLAogICAgYXhpcy50ZXh0LnkubGVmdD1lbGVtZW50X3RleHQoY29sb3I9ImN5YW4zIiksCiAgICBheGlzLnRpdGxlLnkucmlnaHQ9ZWxlbWVudF90ZXh0KGNvbG9yPSJ2aW9sZXRyZWQxIiksCiAgICBheGlzLnRleHQueS5yaWdodD1lbGVtZW50X3RleHQoY29sb3I9InZpb2xldHJlZDEiKQogICkKICAKICAKIAoKYGBgCkhpZXIgd2VyZGVuIG51biBkaWUgQW56YWhsIGRlciBLb21tZW50YXJlIHBybyBCbG9nZWludHJhZyBkZXIgS2FtcGFnbmUgMTk4IHZpc3VhbGlzaWVydC4gQmVpIEJsb2dlaW50cmFnIDcgZ2lidCBlcyBiZXNvbmRlcnMgdmllbGUgS29tbWVudGFyZSwgZGFydW0gd2lyZCBtaXR0ZWxzIEhpc3RvZ3JhbW0gZGllIFZlcnRlaWx1bmcgZGVyIEtvbW1lbnRhci1TZW50aW1lbnRlIGluIEJsb2dlaW50cmFnIDcgZGVyIEthbXBhZ25lIDE5OCBhYmdlYmlsZGV0LgoKYGBge3J9CmdncGxvdCgpICsKICBnZW9tX2xpbmUobWFwcGluZyA9IGFlcyh4PW5lbGxpc2FfMTk4X3Blcl9ibG9nJGJsb2dfaWQsIHk9bmVsbGlzYV8xOThfcGVyX2Jsb2ckY29tbWVudF9jb3VudCksIGNvbD0iYnJvd24yIikgKwogIHhsYWIoIkJsb2cgSUQiKSAgKwogIHlsYWIoIkFuemFobCBLb21tZW50YXJlIikKCm5lbGxpc2FfMTk4XzEyNTYgPC0gbmVsbGlzYV8xOTggJT4lIGZpbHRlcihibG9nX2lkPT0xMjU2KQpuZWxsaXNhXzE5OF8xMjU2JGNvbXBvdW5kICU+JSBoaXN0KGJyZWFrcz0zMCwgbWFpbj0iVmVydGVpbHVuZyBkZXIgS29tbWVudGFyLVNlbnRpbWVudGUgZsO8ciBLYW1wYWduZSAxOTggQmxvZyA3IikKYWJsaW5lKHYgPSBxMywgY29sPSJzcHJpbmdncmVlbjQiLCBsd2Q9MiwgbHR5PTIpCmBgYAoKCgoKIyMjIyBOZWdhdGl2ZSBLb21tZW50YXJlIGluIEthbXBhZ25lIDE4OQpgYGB7cn0KbmVsbGlzYV8xOTggJT4lIAogIGFycmFuZ2UoKGNvbXBvdW5kKSkgJT4lIAogIHNlbGVjdChjb21tZW50X3RleHQsIGJsb2dfaWQsIGNvbXBvdW5kLCBjb21tZW50X2F1dGhvcikKYGBgCgojIyBTdXBlci1uZWdhdGl2ZSBLb21tZW50YXJlCkhpZXIgd2VyZGVuIGVpbiBwYWFyIEJsb2dzIGF1ZiBpaHJlIG5lZ2F0aXZzdGVuIEtvbW1lbnRhcmUgU3RpY2hwcm9iZW5hcnRpZyB1bnRlcnN1Y2h0LgpgYGB7cn0KdG9wbmVnIDwtIEdlclZhZGVyMl9jb21tZW50cyAlPiUgCiAgZmlsdGVyKGJsb2dfaWQgJWluJSBjKDI2MjUsIDIwOTYsIDExNTgpKSAlPiUgCiAgZmlsdGVyKGNvbW1lbnRfYXV0aG9yICE9ICJUYWxpYTgyIikgJT4lIAogIGxlZnRfam9pbihwcm9qZWN0cykgJT4lIAogIGZpbHRlcihjYXRlZ29yeSA9PSAiSGF1c2hhbHQgJiBSZWluaWd1bmciKSAlPiUgCiAgYXJyYW5nZShjb21wb3VuZCkgJT4lIAogIGRpc3RpbmN0KCkgJT4lIAogIGhlYWQoMjApICU+JSAKICBhcnJhbmdlKGJsb2dfaWQpCgp0b3BuZWcKd3JpdGVfdHN2KHRvcG5lZywgZmlsZT0iLi9kYXRhL3RvcF9uZWdhdGl2ZV9rb21tZW50YXJlXzI5Ny50c3YiKQoKYGBgCgoKCgoKIyMgS29tbWVudGFyLVNlbnRpbWVudGUgcHJvIFRlaWxuZWhtZXIKRGllIFRlaWxuZWhtZXIgbmVobWVuIHZlc2NoaWVkZW4gb2Z0IGFuIEthbXBhZ25lbiB0ZWlsLCBzY2hyZWliZW4gdmVyc2NoaWVkZW4gbGFuZ2UgdW5kIGVtb3Rpb24gdW50ZXJzY2hpZWRsaWNoIGdlbGFkZW5lIFRleHRlLiBEYXMgd2lyZCBoaWVyIHVudGVyc3VjaHQuCgpgYGB7cn0KR2VyVmFkZXJfcGVyX3VzZXIgPC0gR2VyVmFkZXIyX2NvbW1lbnRzICU+JSAKICAjIGRhbWl0IHJlY2h0ZmVydGlnZSBpY2ggZGllc2VuIHVuZ2V3w7ZobmxpY2hlbiBTY2hyaXR0CiAgbXV0YXRlKHByb2plY3RfaWQgPSAxKSAlPiUKICAjIGRpZSBwcm9qZWN0X2lkIHdpcmQgaGllciB6dSAxIG11dGllcnQsIHVtIHNww6R0ZXJlcyBTdW1taWVyZW4genUgZXJsZWljaHRlcm4KICAjIGRpZSBjb3VudCgpLUZ1bmt0aW9uIHdhciBpbiBkaWVzZW0gRmFsbCBldHdhcyAiYnVnZ3kiCiAgIyBTdGF0aXN0aWtlbiBwcm8gVXNlcgogIGdyb3VwX2J5KGNvbW1lbnRfYXV0aG9yKSAlPiUgCiAgc3VtbWFyaXNlKAogICAgU2VudGltZW50TWVhbiA9IG1lYW4oY29tcG91bmQpLCAjIFNlbnRpbWVudC1NaXR0ZWx3ZXJ0CiAgICBjb21tZW50X2NvdW50ID0gbigpLCAjIEFuemFobCBoaW50ZXJsYXNzZW5lciBLb21tZW50YXJlCiAgICB3b3JkQ291bnRNZWFuID0gbWVhbih3b3JkQ291bnQpLCAjIGR1cmNoc2Nobml0dGxpY2hlIFdvcnRhbnphaGwgcHJvIEtvbW1lbnRhcgogICAgcHJvamVjdENvdW50ID0gc3VtKHByb2plY3RfaWQpICMgQW56YWhsIHRlaWxnZW5vbW1lbmVyIEthbXBhZ25lbgogICkKCkdlclZhZGVyX3Blcl91c2VyCmBgYAoKSGllciBzaW5kIGVpbiBwYWFyIGluZm9ybWF0aXZlIFBsb3RzIHp1IGRlbiBWZXJ0ZWlsdW5nZW4gZGVyIFVzZXJrb21tZW50YXJlLgpgYGB7cn0KR2VyVmFkZXJfcGVyX3VzZXIkU2VudGltZW50TWVhbiAlPiUgCiAgaGlzdChicmVha3M9NTAsIG1haW49IlZlcnRlaWx1bmcgZGVyIFNlbnRpbWVudGUgcHJvIFVzZXIiKQoKR2VyVmFkZXJfcGVyX3VzZXIkU2VudGltZW50TWVhbiAlPiUgCiAgYm94cGxvdChob3Jpem9udGFsPVRSVUUsIG1haW49IkJveHBsb3QgZGVyIFNlbnRpbWVudGUgcHJvIFVzZXIiKQoKCgpHZXJWYWRlcl9wZXJfdXNlciRjb21tZW50X2NvdW50ICU+JSAKICBib3hwbG90KGhvcml6b250YWw9VFJVRSwgbWFpbj0iQm94cGxvdCBkZXIgS29tbWVudGFyZSBwcm8gVXNlciIpCgoKCkdlclZhZGVyX3Blcl91c2VyJHdvcmRDb3VudE1lYW4gJT4lIAogIGhpc3QoYnJlYWtzPTUwLCBtYWluPSJWZXJ0ZWlsdW5nIGRlciBkdXJjaHNjaG5pdHRsaWNoZW4gS29tbWVudGFybMOkbmdlIHBybyBVc2VyIikKYGBgCgojIyMgR2VuYXVlcmUgVW50ZXJzdWNodHVuZyBkZXMgVXNlcnMgImJsYWNrc3RhciIKRGllIEtvbW1lbnRhcmUgZGVzIFVzZXJzICJibGFja3N0YXIiLCBkZXNzZW4gS29tbWVudGFyZSB0ZW5kZW56aWVsbCBuZWdhdGl2IHNpbmQsIHdlcmRlbiBoaWVyIGhlcmF1c2dlZmlsdGVydCwgZGFtaXQgc2llIGluaGFsdGxpY2ggYW5hbHlzaWVydCB3ZXJkZW4ga8O2bm5lbi4gU2llIHNjaGVpbmVuIEJlc2Nod2VyZGVuIMO8YmVyIExpZWZlcnByb2JsZW1lIHp1IGVudGhhbHRlbi4KCmBgYHtyfQpibGFja3N0YXIgPC0gR2VyVmFkZXIyX2NvbW1lbnRzICU+JSAKICBmaWx0ZXIoY29tbWVudF9hdXRob3IgPT0gImJsYWNrc3RhcjE0ODciKSAlPiUgCiAgc2VsZWN0KGNvbXBvdW5kLCBjb21tZW50X3RleHQpICU+JSAKICBtdXRhdGUoY29tcG91bmQgPSByb3VuZChjb21wb3VuZCwgMikpCmJsYWNrc3RhcgoKIyBTcGVpY2hlcmUgZGllIERhdGVuCndyaXRlX3RzdihibGFja3N0YXIsIGZpbGU9Ii4vZGF0YS9ibGFja3N0YXJfa29tbWVudGFyZS50c3YiKQoKYGBgCgo=